<commit_before>package util

import (
	"bufio"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/valyala/fasthttp"
)

var startTimeUnix = time.Now().Unix()
var clientConnPool sync.Pool

// HTTPOption http client option
type HTTPOption struct {
	// Maximum number of connections which may be established to server
	MaxConns int
	// MaxConnDuration Keep-alive connections are closed after this duration.
	MaxConnDuration time.Duration
	// MaxIdleConnDuration Idle keep-alive connections are closed after this duration.
	MaxIdleConnDuration time.Duration
	// ReadBufferSize Per-connection buffer size for responses' reading.
	ReadBufferSize int
	// WriteBufferSize Per-connection buffer size for requests' writing.
	WriteBufferSize int
	// ReadTimeout Maximum duration for full response reading (including body).
	ReadTimeout time.Duration
	// WriteTimeout Maximum duration for full request writing (including body).
	WriteTimeout time.Duration
	// MaxResponseBodySize Maximum response body size.
	MaxResponseBodySize int
}

// DefaultHTTPOption returns a HTTP Option
func DefaultHTTPOption() *HTTPOption {
	return &HTTPOption{
		MaxConns:            8,
		MaxConnDuration:     time.Minute,
		MaxIdleConnDuration: time.Second * 30,
		ReadBufferSize:      512,
		WriteBufferSize:     256,
		ReadTimeout:         time.Second * 30,
		WriteTimeout:        time.Second * 30,
		MaxResponseBodySize: 1024 * 1024 * 10,
	}
}

// FastHTTPClient fast http client
type FastHTTPClient struct {
	sync.RWMutex

	defaultOption *HTTPOption
	hostClients   map[string]*hostClients
	readerPool    sync.Pool
	writerPool    sync.Pool
}

// NewFastHTTPClient create FastHTTPClient instance
func NewFastHTTPClient() *FastHTTPClient {
	return NewFastHTTPClientOption(nil)
}

// NewFastHTTPClientOption create FastHTTPClient instance with default option
func NewFastHTTPClientOption(defaultOption *HTTPOption) *FastHTTPClient {
	return &FastHTTPClient{
		defaultOption: defaultOption,
		hostClients:   make(map[string]*hostClients),
	}
}

type hostClients struct {
	sync.Mutex

	option      *HTTPOption
	lastUseTime uint32
	connsCount  int
	conns       []*clientConn
}

func (c *hostClients) acquireConn(addr string) (*clientConn, error) {
	var cc *clientConn
	createConn := false
	startCleaner := false

	var n int
	c.Lock()
	n = len(c.conns)
	if n == 0 {
		maxConns := c.option.MaxConns
		if maxConns <= 0 {
			maxConns = fasthttp.DefaultMaxConnsPerHost
		}
		if c.connsCount < maxConns {
			c.connsCount++
			createConn = true
		}
		if createConn && c.connsCount == 1 {
			startCleaner = true
		}
	} else {
		n--
		cc = c.conns[n]
		c.conns = c.conns[:n]
	}
	c.Unlock()

	if cc != nil {
		return cc, nil
	}
	if !createConn {
		return nil, fasthttp.ErrNoFreeConns
	}

	conn, err := dialAddr(addr)
	if err != nil {
		c.decConnsCount()
		return nil, err
	}
	cc = acquireClientConn(conn)

	if startCleaner {
		go c.connsCleaner()
	}
	return cc, nil
}

func (c *hostClients) decConnsCount() {
	c.Lock()
	c.connsCount--
	c.Unlock()
}

func (c *hostClients) releaseConn(cc *clientConn) {
	cc.lastUseTime = time.Now()
	c.Lock()
	c.conns = append(c.conns, cc)
	c.Unlock()
}

func (c *hostClients) connsCleaner() {
	var (
		scratch             []*clientConn
		mustStop            bool
		maxIdleConnDuration = c.option.MaxIdleConnDuration
	)

	for {
		currentTime := time.Now()

		c.Lock()
		conns := c.conns
		n := len(conns)
		i := 0
		for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration {
			i++
		}
		mustStop = (c.connsCount == i)
		scratch = append(scratch[:0], conns[:i]...)
		if i > 0 {
			m := copy(conns, conns[i:])
			for i = m; i < n; i++ {
				conns[i] = nil
			}
			c.conns = conns[:m]
		}
		c.Unlock()

		for i, cc := range scratch {
			c.closeConn(cc)
			scratch[i] = nil
		}
		if mustStop {
			break
		}
		time.Sleep(maxIdleConnDuration)
	}
}

func (c *hostClients) closeConn(cc *clientConn) {
	c.decConnsCount()
	cc.c.Close()
	releaseClientConn(cc)
}

type clientConn struct {
	c net.Conn

	createdTime time.Time
	lastUseTime time.Time

	lastReadDeadlineTime  time.Time
	lastWriteDeadlineTime time.Time
}

// Do do a http request
func (c *FastHTTPClient) Do(req *fasthttp.Request, addr string, option *HTTPOption) (*fasthttp.Response, error) {
	resp, retry, err := c.do(req, addr, option)
	if err != nil && retry && isIdempotent(req) {
		resp, _, err = c.do(req, addr, option)
	}
	if err == io.EOF {
		err = fasthttp.ErrConnectionClosed
	}
	return resp, err
}

func (c *FastHTTPClient) do(req *fasthttp.Request, addr string, option *HTTPOption) (*fasthttp.Response, bool, error) {
	resp := fasthttp.AcquireResponse()
	ok, err := c.doNonNilReqResp(req, resp, addr, option)
	return resp, ok, err
}

func (c *FastHTTPClient) doNonNilReqResp(req *fasthttp.Request, resp *fasthttp.Response, addr string, option *HTTPOption) (bool, error) {
	if req == nil {
		panic("BUG: req cannot be nil")
	}
	if resp == nil {
		panic("BUG: resp cannot be nil")
	}

	opt := option
	if opt == nil {
		opt = c.defaultOption
	}

	var hc *hostClients
	var ok bool
	c.Lock()
	if hc, ok = c.hostClients[addr]; !ok {
		hc = &hostClients{option: opt}
		c.hostClients[addr] = hc
	}
	c.Unlock()

	atomic.StoreUint32(&hc.lastUseTime, uint32(time.Now().Unix()-startTimeUnix))

	// Free up resources occupied by response before sending the request,
	// so the GC may reclaim these resources (e.g. response body).
	resp.Reset()

	cc, err := hc.acquireConn(addr)
	if err != nil {
		return false, err
	}
	conn := cc.c

	// set write deadline
	if opt.WriteTimeout > 0 {
		// Optimization: update write deadline only if more than 25%
		// of the last write deadline exceeded.
		// See https://github.com/golang/go/issues/15133 for details.
		currentTime := time.Now()
		if currentTime.Sub(cc.lastWriteDeadlineTime) > (opt.WriteTimeout >> 2) {
			if err = conn.SetWriteDeadline(currentTime.Add(opt.WriteTimeout)); err != nil {
				hc.closeConn(cc)
				return true, err
			}
			cc.lastWriteDeadlineTime = currentTime
		}
	}

	resetConnection := false
	if opt.MaxConnDuration > 0 && time.Since(cc.createdTime) > opt.MaxConnDuration && !req.ConnectionClose() {
		req.SetConnectionClose()
		resetConnection = true
	}

	bw := c.acquireWriter(conn, opt)
	err = req.Write(bw)

	if resetConnection {
		req.Header.ResetConnectionClose()
	}

	if err == nil {
		err = bw.Flush()
	}
	if err != nil {
		c.releaseWriter(bw)
		hc.closeConn(cc)
		return true, err
	}
	c.releaseWriter(bw)

	// set read readline
	if opt.ReadTimeout > 0 {
		// Optimization: update read deadline only if more than 25%
		// of the last read deadline exceeded.
		// See https://github.com/golang/go/issues/15133 for details.
		currentTime := time.Now()
		if currentTime.Sub(cc.lastReadDeadlineTime) > (opt.ReadTimeout >> 2) {
			if err = conn.SetReadDeadline(currentTime.Add(opt.ReadTimeout)); err != nil {
				hc.closeConn(cc)
				return true, err
			}
			cc.lastReadDeadlineTime = currentTime
		}
	}

	if !req.Header.IsGet() && req.Header.IsHead() {
		resp.SkipBody = true
	}

	br := c.acquireReader(conn, opt)
	if err = resp.ReadLimitBody(br, opt.MaxResponseBodySize); err != nil {
		c.releaseReader(br)
		hc.closeConn(cc)
		if err == io.EOF {
			return true, err
		}
		return false, err
	}
	c.releaseReader(br)

	if resetConnection || req.ConnectionClose() || resp.ConnectionClose() {
		hc.closeConn(cc)
	} else {
		hc.releaseConn(cc)
	}

	return false, err
}

func dialAddr(addr string) (net.Conn, error) {
	conn, err := fasthttp.Dial(addr)
	if err != nil {
		return nil, err
	}
	if conn == nil {
		panic("BUG: DialFunc returned (nil, nil)")
	}

	return conn, nil
}

func (c *FastHTTPClient) acquireWriter(conn net.Conn, opt *HTTPOption) *bufio.Writer {
	v := c.writerPool.Get()
	if v == nil {
		return bufio.NewWriterSize(conn, opt.WriteBufferSize)
	}
	bw := v.(*bufio.Writer)
	bw.Reset(conn)
	return bw
}

func (c *FastHTTPClient) releaseWriter(bw *bufio.Writer) {
	c.writerPool.Put(bw)
}

func (c *FastHTTPClient) acquireReader(conn net.Conn, opt *HTTPOption) *bufio.Reader {
	v := c.readerPool.Get()
	if v == nil {
		return bufio.NewReaderSize(conn, opt.ReadBufferSize)
	}
	br := v.(*bufio.Reader)
	br.Reset(conn)
	return br
}

func (c *FastHTTPClient) releaseReader(br *bufio.Reader) {
	c.readerPool.Put(br)
}

func isIdempotent(req *fasthttp.Request) bool {
	return req.Header.IsGet() || req.Header.IsHead() || req.Header.IsPut()
}

func acquireClientConn(conn net.Conn) *clientConn {
	v := clientConnPool.Get()
	if v == nil {
		v = &clientConn{}
	}
	cc := v.(*clientConn)
	cc.c = conn
	cc.createdTime = time.Now()
	return cc
}

func releaseClientConn(cc *clientConn) {
	cc.c = nil
	clientConnPool.Put(cc)
}
<commit_msg>fix: start too many cleaner goroutines<commit_after>package util

import (
	"bufio"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/valyala/fasthttp"
)

var startTimeUnix = time.Now().Unix()
var clientConnPool sync.Pool

// HTTPOption http client option
type HTTPOption struct {
	// Maximum number of connections which may be established to server
	MaxConns int
	// MaxConnDuration Keep-alive connections are closed after this duration.
	MaxConnDuration time.Duration
	// MaxIdleConnDuration Idle keep-alive connections are closed after this duration.
	MaxIdleConnDuration time.Duration
	// ReadBufferSize Per-connection buffer size for responses' reading.
	ReadBufferSize int
	// WriteBufferSize Per-connection buffer size for requests' writing.
	WriteBufferSize int
	// ReadTimeout Maximum duration for full response reading (including body).
	ReadTimeout time.Duration
	// WriteTimeout Maximum duration for full request writing (including body).
	WriteTimeout time.Duration
	// MaxResponseBodySize Maximum response body size.
	MaxResponseBodySize int
}

// DefaultHTTPOption returns a HTTP Option
func DefaultHTTPOption() *HTTPOption {
	return &HTTPOption{
		MaxConns:            8,
		MaxConnDuration:     time.Minute,
		MaxIdleConnDuration: time.Second * 30,
		ReadBufferSize:      512,
		WriteBufferSize:     256,
		ReadTimeout:         time.Second * 30,
		WriteTimeout:        time.Second * 30,
		MaxResponseBodySize: 1024 * 1024 * 10,
	}
}

// FastHTTPClient fast http client
type FastHTTPClient struct {
	sync.RWMutex

	defaultOption *HTTPOption
	hostClients   map[string]*hostClients
	readerPool    sync.Pool
	writerPool    sync.Pool
}

// NewFastHTTPClient create FastHTTPClient instance
func NewFastHTTPClient() *FastHTTPClient {
	return NewFastHTTPClientOption(nil)
}

// NewFastHTTPClientOption create FastHTTPClient instance with default option
func NewFastHTTPClientOption(defaultOption *HTTPOption) *FastHTTPClient {
	return &FastHTTPClient{
		defaultOption: defaultOption,
		hostClients:   make(map[string]*hostClients),
	}
}

type hostClients struct {
	sync.Mutex

	startedCleaner uint64
	option         *HTTPOption
	lastUseTime    uint32
	connsCount     int
	conns          []*clientConn
}

func (c *hostClients) acquireConn(addr string) (*clientConn, error) {
	var cc *clientConn
	createConn := false
	startCleaner := false

	var n int
	c.Lock()
	n = len(c.conns)
	if n == 0 {
		maxConns := c.option.MaxConns
		if maxConns <= 0 {
			maxConns = fasthttp.DefaultMaxConnsPerHost
		}
		if c.connsCount < maxConns {
			c.connsCount++
			createConn = true
		}
		if createConn && c.connsCount == 1 {
			startCleaner = true
		}
	} else {
		n--
		cc = c.conns[n]
		c.conns = c.conns[:n]
	}
	c.Unlock()

	if cc != nil {
		return cc, nil
	}
	if !createConn {
		return nil, fasthttp.ErrNoFreeConns
	}

	conn, err := dialAddr(addr)
	if err != nil {
		c.decConnsCount()
		return nil, err
	}
	cc = acquireClientConn(conn)

	if startCleaner {
		if atomic.SwapUint64(&c.startedCleaner, 1) == 0 {
			go c.connsCleaner()
		}
	}
	return cc, nil
}

func (c *hostClients) decConnsCount() {
	c.Lock()
	c.connsCount--
	c.Unlock()
}

func (c *hostClients) releaseConn(cc *clientConn) {
	cc.lastUseTime = time.Now()
	c.Lock()
	c.conns = append(c.conns, cc)
	c.Unlock()
}

func (c *hostClients) connsCleaner() {
	var (
		scratch             []*clientConn
		mustStop            bool
		maxIdleConnDuration = c.option.MaxIdleConnDuration
	)

	for {
		currentTime := time.Now()

		c.Lock()
		conns := c.conns
		n := len(conns)
		i := 0
		for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration {
			i++
		}
		mustStop = (c.connsCount == i)
		scratch = append(scratch[:0], conns[:i]...)
		if i > 0 {
			m := copy(conns, conns[i:])
			for i = m; i < n; i++ {
				conns[i] = nil
			}
			c.conns = conns[:m]
		}
		c.Unlock()

		for i, cc := range scratch {
			c.closeConn(cc)
			scratch[i] = nil
		}
		if mustStop {
			break
		}
		time.Sleep(maxIdleConnDuration)
	}

	atomic.StoreUint64(&c.startedCleaner, 0)
}

func (c *hostClients) closeConn(cc *clientConn) {
	c.decConnsCount()
	cc.c.Close()
	releaseClientConn(cc)
}

type clientConn struct {
	c net.Conn

	createdTime time.Time
	lastUseTime time.Time

	lastReadDeadlineTime  time.Time
	lastWriteDeadlineTime time.Time
}

// Do do a http request
func (c *FastHTTPClient) Do(req *fasthttp.Request, addr string, option *HTTPOption) (*fasthttp.Response, error) {
	resp, retry, err := c.do(req, addr, option)
	if err != nil && retry && isIdempotent(req) {
		resp, _, err = c.do(req, addr, option)
	}
	if err == io.EOF {
		err = fasthttp.ErrConnectionClosed
	}
	return resp, err
}

func (c *FastHTTPClient) do(req *fasthttp.Request, addr string, option *HTTPOption) (*fasthttp.Response, bool, error) {
	resp := fasthttp.AcquireResponse()
	ok, err := c.doNonNilReqResp(req, resp, addr, option)
	return resp, ok, err
}

func (c *FastHTTPClient) doNonNilReqResp(req *fasthttp.Request, resp *fasthttp.Response, addr string, option *HTTPOption) (bool, error) {
	if req == nil {
		panic("BUG: req cannot be nil")
	}
	if resp == nil {
		panic("BUG: resp cannot be nil")
	}

	opt := option
	if opt == nil {
		opt = c.defaultOption
	}

	var hc *hostClients
	var ok bool
	c.Lock()
	if hc, ok = c.hostClients[addr]; !ok {
		hc = &hostClients{option: opt}
		c.hostClients[addr] = hc
	}
	c.Unlock()

	atomic.StoreUint32(&hc.lastUseTime, uint32(time.Now().Unix()-startTimeUnix))

	// Free up resources occupied by response before sending the request,
	// so the GC may reclaim these resources (e.g. response body).
	resp.Reset()

	cc, err := hc.acquireConn(addr)
	if err != nil {
		return false, err
	}
	conn := cc.c

	// set write deadline
	if opt.WriteTimeout > 0 {
		// Optimization: update write deadline only if more than 25%
		// of the last write deadline exceeded.
		// See https://github.com/golang/go/issues/15133 for details.
		currentTime := time.Now()
		if currentTime.Sub(cc.lastWriteDeadlineTime) > (opt.WriteTimeout >> 2) {
			if err = conn.SetWriteDeadline(currentTime.Add(opt.WriteTimeout)); err != nil {
				hc.closeConn(cc)
				return true, err
			}
			cc.lastWriteDeadlineTime = currentTime
		}
	}

	resetConnection := false
	if opt.MaxConnDuration > 0 && time.Since(cc.createdTime) > opt.MaxConnDuration && !req.ConnectionClose() {
		req.SetConnectionClose()
		resetConnection = true
	}

	bw := c.acquireWriter(conn, opt)
	err = req.Write(bw)

	if resetConnection {
		req.Header.ResetConnectionClose()
	}

	if err == nil {
		err = bw.Flush()
	}
	if err != nil {
		c.releaseWriter(bw)
		hc.closeConn(cc)
		return true, err
	}
	c.releaseWriter(bw)

	// set read readline
	if opt.ReadTimeout > 0 {
		// Optimization: update read deadline only if more than 25%
		// of the last read deadline exceeded.
		// See https://github.com/golang/go/issues/15133 for details.
		currentTime := time.Now()
		if currentTime.Sub(cc.lastReadDeadlineTime) > (opt.ReadTimeout >> 2) {
			if err = conn.SetReadDeadline(currentTime.Add(opt.ReadTimeout)); err != nil {
				hc.closeConn(cc)
				return true, err
			}
			cc.lastReadDeadlineTime = currentTime
		}
	}

	if !req.Header.IsGet() && req.Header.IsHead() {
		resp.SkipBody = true
	}

	br := c.acquireReader(conn, opt)
	if err = resp.ReadLimitBody(br, opt.MaxResponseBodySize); err != nil {
		c.releaseReader(br)
		hc.closeConn(cc)
		if err == io.EOF {
			return true, err
		}
		return false, err
	}
	c.releaseReader(br)

	if resetConnection || req.ConnectionClose() || resp.ConnectionClose() {
		hc.closeConn(cc)
	} else {
		hc.releaseConn(cc)
	}

	return false, err
}

func dialAddr(addr string) (net.Conn, error) {
	conn, err := fasthttp.Dial(addr)
	if err != nil {
		return nil, err
	}
	if conn == nil {
		panic("BUG: DialFunc returned (nil, nil)")
	}

	return conn, nil
}

func (c *FastHTTPClient) acquireWriter(conn net.Conn, opt *HTTPOption) *bufio.Writer {
	v := c.writerPool.Get()
	if v == nil {
		return bufio.NewWriterSize(conn, opt.WriteBufferSize)
	}
	bw := v.(*bufio.Writer)
	bw.Reset(conn)
	return bw
}

func (c *FastHTTPClient) releaseWriter(bw *bufio.Writer) {
	c.writerPool.Put(bw)
}

func (c *FastHTTPClient) acquireReader(conn net.Conn, opt *HTTPOption) *bufio.Reader {
	v := c.readerPool.Get()
	if v == nil {
		return bufio.NewReaderSize(conn, opt.ReadBufferSize)
	}
	br := v.(*bufio.Reader)
	br.Reset(conn)
	return br
}

func (c *FastHTTPClient) releaseReader(br *bufio.Reader) {
	c.readerPool.Put(br)
}

func isIdempotent(req *fasthttp.Request) bool {
	return req.Header.IsGet() || req.Header.IsHead() || req.Header.IsPut()
}

func acquireClientConn(conn net.Conn) *clientConn {
	v := clientConnPool.Get()
	if v == nil {
		v = &clientConn{}
	}
	cc := v.(*clientConn)
	cc.c = conn
	cc.createdTime = time.Now()
	return cc
}

func releaseClientConn(cc *clientConn) {
	cc.c = nil
	clientConnPool.Put(cc)
}
<|endoftext|>


<commit_before>package null

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/reflexionhealth/vanilla/date"
	"github.com/satori/go.uuid"
)

var JsonNull = []byte("null")

// Bool is a nullable boolean that doesn't require an extra allocation or dereference.
// The builting sql package has a NullBool, but it doesn't implement json.Marshaler.
type Bool sql.NullBool

func (n *Bool) Set(value bool) {
	n.Valid = true
	n.Bool = value
}

// Implement sql.Scanner interface
func (n *Bool) Scan(src interface{}) error {
	return (*sql.NullBool)(n).Scan(src)
}

// Implement driver.Valuer interface
func (n Bool) Value() (driver.Value, error) {
	return (sql.NullBool)(n).Value()
}

// Implement json.Marshaler interface
func (n Bool) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Bool)
	} else {
		return []byte("null"), nil
	}
}

// Implement json.Unmarshaler interface
func (n *Bool) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Bool = false
	} else {
		err := json.Unmarshal(bytes, &n.Bool)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// String is a nullable string that doesn't require an extra allocation or dereference.
// The builting sql package has a NullString, but it doesn't implement json.Marshaler.
type String sql.NullString

func (n *String) Set(value string) {
	n.Valid = true
	n.String = value
}

// Implement sql.Scanner interface
func (n *String) Scan(src interface{}) error {
	return (*sql.NullString)(n).Scan(src)
}

// Implement driver.Valuer interface
func (n String) Value() (driver.Value, error) {
	return (sql.NullString)(n).Value()
}

// Implement json.Marshaler interface
func (n String) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.String)
	} else {
		return []byte("null"), nil
	}
}

// Implement json.Unmarshaler interface
func (n *String) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.String = ""
	} else {
		err := json.Unmarshal(bytes, &n.String)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

type Float struct {
	Float float32
	Valid bool
}

func (n *Float) Set(value float32) {
	n.Valid = true
	n.Float = value
}

func (n *Float) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		n.Float = 0.0
		return nil
	}

	switch t := src.(type) {
	case string:
		f64, err := strconv.ParseFloat(t, 32)
		if err != nil {
			return fmt.Errorf("sql/null: converting driver.Value type %T (%q) to a null.Float: %v", src, t, strconvErr(err))
		}
		n.Set(float32(f64))
	case int64, float32:
		n.Set(t.(float32))
	case float64:
		n.Set(float32(t))
	}

	return nil
}

// Implement driver.Valuer interface
func (n Float) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return float64(n.Float), nil
	}
}

// Implement json.Marshaler interface
func (n Float) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Float)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Float) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.Float = 0.0
		return nil
	}

	err := json.Unmarshal(bytes, &n.Float)
	if err != nil {
		return err
	}

	n.Valid = true
	return nil
}

// Int is a nullable int that doesn't require an extra allocation or dereference.
// The builting sql package has a NullInt64, but it doesn't implement json.Marshaler
// and is an int64 instead of an int.
type Int struct {
	Int   int
	Valid bool
}

func (n *Int) Set(value int) {
	n.Valid = true
	n.Int = value
}

// Implement sql.Scanner interface
func (n *Int) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		n.Int = 0
		return nil
	}
	switch t := src.(type) {
	case string:
		i64, err := strconv.ParseInt(t, 10, 64)
		if err != nil {
			return fmt.Errorf("sql/null: converting driver.Value type %T (%q) to a null.Int: %v", src, t, strconvErr(err))
		}
		n.Set(int(i64))
	case int64:
		n.Set(int(t))
	}
	return nil
}

// Implement driver.Valuer interface
func (n Int) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Int, nil
	}
}

// Implement json.Marshaler interface
func (n Int) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Int)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Int) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.Int = 0
		return nil
	}

	err := json.Unmarshal(bytes, &n.Int)
	if err != nil {
		return err
	}

	n.Valid = true
	return nil
}

// Time is a nullable time.Time that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Time struct {
	Time  time.Time
	Valid bool
}

func (n *Time) Set(value time.Time) {
	n.Valid = true
	n.Time = value
}

// Implement sql.Scanner interface
func (n *Time) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		return nil
	}

	switch t := src.(type) {
	case string:
		var err error
		n.Time, err = time.Parse("2006-01-02 15:04:05", t)
		if err != nil {
			return err
		}
	case []byte:
		var err error
		n.Time, err = time.Parse("2006-01-02 15:04:05", string(t))
		if err != nil {
			return err
		}
	case time.Time:
		n.Time = t
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	n.Valid = true
	return nil
}

// Implement driver.Valuer interface
func (n Time) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Time, nil
	}
}

// Implement json.Marshaler interface
func (n Time) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return n.Time.MarshalJSON()
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Time) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Time = time.Time{}
	} else {
		err := n.Time.UnmarshalJSON(bytes)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// Date is a nullable date.Date that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Date struct {
	Date  date.Date
	Valid bool
}

func (n *Date) Set(value date.Date) {
	n.Valid = true
	n.Date = value
}

// Implement sql.Scanner interface
func (n *Date) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		return nil
	}

	var srcTime Time
	switch t := src.(type) {
	case string:
		var err error
		srcTime.Time, err = time.Parse("2006-01-02", t)
		if err != nil {
			return err
		}
	case []byte:
		var err error
		srcTime.Time, err = time.Parse("2006-01-02", string(t))
		if err != nil {
			return err
		}
	case time.Time:
		srcTime.Time = t
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	n.Valid = true
	n.Date = date.From(srcTime.Time)
	return nil
}

// Implement driver.Valuer interface
func (n Date) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Date.Value()
	}
}

// Implement json.Marshaler interface
func (n Date) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return n.Date.MarshalJSON()
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Date) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Date = date.Date{}
	} else {
		err := n.Date.UnmarshalJSON(bytes)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// Uuid is a nullable date.Date that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Uuid struct {
	Uuid  uuid.UUID
	Valid bool
}

func (id *Uuid) Set(value uuid.UUID) {
	id.Valid = true
	id.Uuid = value
}

// Implement sql.Scanner interface.
func (id *Uuid) Scan(src interface{}) error {
	id.Valid = false
	if src == nil {
		return nil
	}

	switch u := src.(type) {
	case string:
		var err error

		switch len(u) {
		case 32, 36:
			id.Uuid, err = uuid.FromString(u)
		case 16:
			id.Uuid, err = uuid.FromBytes([]byte(u))
		default:
			err = errors.New("sql/null: scan value for uuid was not 16, 32, or 36 bytes long")
		}

		if err != nil {
			return err
		}
	case []byte:
		var err error

		switch len(u) {
		case 32, 36:
			id.Uuid, err = uuid.FromString(string(u))
		case 16:
			id.Uuid, err = uuid.FromBytes(u)
		default:
			err = errors.New("sql/null: scan value for uuid was not 16, 32, or 36 bytes long")
		}

		if err != nil {
			return err
		}
	case uuid.UUID:
		id.Uuid = u
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	id.Valid = true
	return nil
}

// Implement driver.Valuer interface
func (id Uuid) Value() (driver.Value, error) {
	if !id.Valid {
		return nil, nil
	} else {
		return id.Uuid.Value()
	}
}

// Implement json.Marshaler interface
func (id Uuid) MarshalJSON() ([]byte, error) {
	if id.Valid {
		return json.Marshal(id.Uuid)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (id *Uuid) UnmarshalJSON(bytes []byte) error {
	id.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		id.Uuid = uuid.UUID{} //date.Date{}
	} else {
		err := json.Unmarshal(bytes, &id.Uuid)
		if err != nil {
			return err
		} else {
			id.Valid = true
		}
	}
	return nil
}

// copied from database/sql/convert.go
func strconvErr(err error) error {
	if ne, ok := err.(*strconv.NumError); ok {
		return ne.Err
	}
	return err
}
<commit_msg>null: use float64 instead of float32<commit_after>package null

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/reflexionhealth/vanilla/date"
	"github.com/satori/go.uuid"
)

var JsonNull = []byte("null")

// Bool is a nullable boolean that doesn't require an extra allocation or dereference.
// The builting sql package has a NullBool, but it doesn't implement json.Marshaler.
type Bool sql.NullBool

func (n *Bool) Set(value bool) {
	n.Valid = true
	n.Bool = value
}

// Implement sql.Scanner interface
func (n *Bool) Scan(src interface{}) error {
	return (*sql.NullBool)(n).Scan(src)
}

// Implement driver.Valuer interface
func (n Bool) Value() (driver.Value, error) {
	return (sql.NullBool)(n).Value()
}

// Implement json.Marshaler interface
func (n Bool) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Bool)
	} else {
		return []byte("null"), nil
	}
}

// Implement json.Unmarshaler interface
func (n *Bool) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Bool = false
	} else {
		err := json.Unmarshal(bytes, &n.Bool)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// String is a nullable string that doesn't require an extra allocation or dereference.
// The builting sql package has a NullString, but it doesn't implement json.Marshaler.
type String sql.NullString

func (n *String) Set(value string) {
	n.Valid = true
	n.String = value
}

// Implement sql.Scanner interface
func (n *String) Scan(src interface{}) error {
	return (*sql.NullString)(n).Scan(src)
}

// Implement driver.Valuer interface
func (n String) Value() (driver.Value, error) {
	return (sql.NullString)(n).Value()
}

// Implement json.Marshaler interface
func (n String) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.String)
	} else {
		return []byte("null"), nil
	}
}

// Implement json.Unmarshaler interface
func (n *String) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.String = ""
	} else {
		err := json.Unmarshal(bytes, &n.String)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

type Float struct {
	Float float64
	Valid bool
}

func (n *Float) Set(value float64) {
	n.Valid = true
	n.Float = value
}

func (n *Float) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		n.Float = 0.0
		return nil
	}

	switch t := src.(type) {
	case string:
		f64, err := strconv.ParseFloat(t, 64)
		if err != nil {
			return fmt.Errorf("sql/null: converting driver.Value type %T (%q) to a null.Float: %v", src, t, strconvErr(err))
		}
		n.Set(f64)
	case float64:
		n.Set(t)
	case float32:
		n.Set(float64(t))
	case int64:
		n.Set(float64(t))
	case int32:
		n.Set(float64(t))
	}

	return nil
}

// Implement driver.Valuer interface
func (n Float) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return float64(n.Float), nil
	}
}

// Implement json.Marshaler interface
func (n Float) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Float)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Float) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.Float = 0.0
		return nil
	}

	err := json.Unmarshal(bytes, &n.Float)
	if err != nil {
		return err
	}

	n.Valid = true
	return nil
}

// Int is a nullable int that doesn't require an extra allocation or dereference.
// The builting sql package has a NullInt64, but it doesn't implement json.Marshaler
// and is an int64 instead of an int.
type Int struct {
	Int   int
	Valid bool
}

func (n *Int) Set(value int) {
	n.Valid = true
	n.Int = value
}

// Implement sql.Scanner interface
func (n *Int) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		n.Int = 0
		return nil
	}
	switch t := src.(type) {
	case string:
		i64, err := strconv.ParseInt(t, 10, 64)
		if err != nil {
			return fmt.Errorf("sql/null: converting driver.Value type %T (%q) to a null.Int: %v", src, t, strconvErr(err))
		}
		n.Set(int(i64))
	case int64:
		n.Set(int(t))
	}
	return nil
}

// Implement driver.Valuer interface
func (n Int) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Int, nil
	}
}

// Implement json.Marshaler interface
func (n Int) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return json.Marshal(n.Int)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Int) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == "null" {
		n.Int = 0
		return nil
	}

	err := json.Unmarshal(bytes, &n.Int)
	if err != nil {
		return err
	}

	n.Valid = true
	return nil
}

// Time is a nullable time.Time that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Time struct {
	Time  time.Time
	Valid bool
}

func (n *Time) Set(value time.Time) {
	n.Valid = true
	n.Time = value
}

// Implement sql.Scanner interface
func (n *Time) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		return nil
	}

	switch t := src.(type) {
	case string:
		var err error
		n.Time, err = time.Parse("2006-01-02 15:04:05", t)
		if err != nil {
			return err
		}
	case []byte:
		var err error
		n.Time, err = time.Parse("2006-01-02 15:04:05", string(t))
		if err != nil {
			return err
		}
	case time.Time:
		n.Time = t
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	n.Valid = true
	return nil
}

// Implement driver.Valuer interface
func (n Time) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Time, nil
	}
}

// Implement json.Marshaler interface
func (n Time) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return n.Time.MarshalJSON()
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Time) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Time = time.Time{}
	} else {
		err := n.Time.UnmarshalJSON(bytes)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// Date is a nullable date.Date that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Date struct {
	Date  date.Date
	Valid bool
}

func (n *Date) Set(value date.Date) {
	n.Valid = true
	n.Date = value
}

// Implement sql.Scanner interface
func (n *Date) Scan(src interface{}) error {
	n.Valid = false
	if src == nil {
		return nil
	}

	var srcTime Time
	switch t := src.(type) {
	case string:
		var err error
		srcTime.Time, err = time.Parse("2006-01-02", t)
		if err != nil {
			return err
		}
	case []byte:
		var err error
		srcTime.Time, err = time.Parse("2006-01-02", string(t))
		if err != nil {
			return err
		}
	case time.Time:
		srcTime.Time = t
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	n.Valid = true
	n.Date = date.From(srcTime.Time)
	return nil
}

// Implement driver.Valuer interface
func (n Date) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	} else {
		return n.Date.Value()
	}
}

// Implement json.Marshaler interface
func (n Date) MarshalJSON() ([]byte, error) {
	if n.Valid {
		return n.Date.MarshalJSON()
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (n *Date) UnmarshalJSON(bytes []byte) error {
	n.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		n.Date = date.Date{}
	} else {
		err := n.Date.UnmarshalJSON(bytes)
		if err != nil {
			return err
		} else {
			n.Valid = true
		}
	}
	return nil
}

// Uuid is a nullable date.Date that doesn't require an extra allocation or dereference.
// It supports encoding/decoding with database/sql, encoding/gob, and encoding/json.
type Uuid struct {
	Uuid  uuid.UUID
	Valid bool
}

func (id *Uuid) Set(value uuid.UUID) {
	id.Valid = true
	id.Uuid = value
}

// Implement sql.Scanner interface.
func (id *Uuid) Scan(src interface{}) error {
	id.Valid = false
	if src == nil {
		return nil
	}

	switch u := src.(type) {
	case string:
		var err error

		switch len(u) {
		case 32, 36:
			id.Uuid, err = uuid.FromString(u)
		case 16:
			id.Uuid, err = uuid.FromBytes([]byte(u))
		default:
			err = errors.New("sql/null: scan value for uuid was not 16, 32, or 36 bytes long")
		}

		if err != nil {
			return err
		}
	case []byte:
		var err error

		switch len(u) {
		case 32, 36:
			id.Uuid, err = uuid.FromString(string(u))
		case 16:
			id.Uuid, err = uuid.FromBytes(u)
		default:
			err = errors.New("sql/null: scan value for uuid was not 16, 32, or 36 bytes long")
		}

		if err != nil {
			return err
		}
	case uuid.UUID:
		id.Uuid = u
	default:
		return errors.New("sql/null: scan value was not a Time, []byte, string, or nil")
	}

	id.Valid = true
	return nil
}

// Implement driver.Valuer interface
func (id Uuid) Value() (driver.Value, error) {
	if !id.Valid {
		return nil, nil
	} else {
		return id.Uuid.Value()
	}
}

// Implement json.Marshaler interface
func (id Uuid) MarshalJSON() ([]byte, error) {
	if id.Valid {
		return json.Marshal(id.Uuid)
	} else {
		return JsonNull, nil
	}
}

// Implement json.Unmarshaler interface
func (id *Uuid) UnmarshalJSON(bytes []byte) error {
	id.Valid = false
	if bytes == nil || string(bytes) == `""` || string(bytes) == "null" {
		id.Uuid = uuid.UUID{} //date.Date{}
	} else {
		err := json.Unmarshal(bytes, &id.Uuid)
		if err != nil {
			return err
		} else {
			id.Valid = true
		}
	}
	return nil
}

// copied from database/sql/convert.go
func strconvErr(err error) error {
	if ne, ok := err.(*strconv.NumError); ok {
		return ne.Err
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// +build !appengine

// Package socket implements an WebSocket-based playground backend.
// Clients connect to a websocket handler and send run/kill commands, and
// the server sends the output and exit status of the running processes.
// Multiple clients running multiple processes may be served concurrently.
// The wire format is JSON and is described by the Message type.
//
// This will not run on App Engine as WebSockets are not supported there.
package socket

import (
	"bytes"
	"encoding/json"
	"errors"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"code.google.com/p/go.net/websocket"
)

// Handler implements a WebSocket handler for a client connection.
var Handler = websocket.Handler(socketHandler)

// Environ provides an environment when a binary, such as the go tool, is
// invoked.
var Environ func() []string = os.Environ

const (
	// The maximum number of messages to send per session (avoid flooding).
	msgLimit = 1000

	// Batch messages sent in this interval and send as a single message.
	msgDelay = 10 * time.Millisecond
)

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id      string // client-provided unique id for the process
	Kind    string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body    string
	Options *Options `json:",omitempty"`
}

// Options specify additional message options.
type Options struct {
	Race bool // use -race flag when building code (for "run" only)
}

// socketHandler handles the websocket connection for a given present session.
// It handles transcoding Messages to and from JSON format, and starting
// and killing processes.
func socketHandler(c *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and send to the in channel.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Start and kill processes and handle errors.
	proc := make(map[string]*process)
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = startProcess(m.Id, m.Body, lOut, m.Options)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			if err != io.EOF {
				// A encode or decode has failed; bail.
				log.Println(err)
			}
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// process represents a running process.
type process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
	bin  string
}

// startProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func startProcess(id, body string, out chan<- *Message, opt *Options) *process {
	p := &process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	var err error
	if path, args := shebang(body); path != "" {
		err = p.startProcess(path, args, body)
	} else {
		err = p.start(body, opt)
	}
	if err != nil {
		p.end(err)
		return nil
	}
	go p.wait()
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *process) Kill() {
	if p == nil {
		return
	}
	p.run.Process.Kill()
	<-p.done // block until process exits
}

// shebang looks for a shebang ('#!') at the beginning of the passed string.
// If found, it returns the path and args after the shebang.
// args includes the command as args[0].
func shebang(body string) (path string, args []string) {
	body = strings.TrimSpace(body)
	if !strings.HasPrefix(body, "#!") {
		return "", nil
	}
	if i := strings.Index(body, "\n"); i >= 0 {
		body = body[:i]
	}
	fs := strings.Fields(body[2:])
	return fs[0], fs
}

// startProcess starts a given program given its path and passing the given body
// to the command standard input.
func (p *process) startProcess(path string, args []string, body string) error {
	cmd := &exec.Cmd{
		Path:   path,
		Args:   args,
		Stdin:  strings.NewReader(body),
		Stdout: &messageWriter{id: p.id, kind: "stdout", out: p.out},
		Stderr: &messageWriter{id: p.id, kind: "stderr", out: p.out},
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	p.run = cmd
	return nil
}

// start builds and starts the given program, sending its output to p.out,
// and stores the running *exec.Cmd in the run field.
func (p *process) start(body string, opt *Options) error {
	// We "go build" and then exec the binary so that the
	// resultant *exec.Cmd is a handle to the user's program
	// (rather than the go tool process).
	// This makes Kill work.

	bin := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := bin + ".go"
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write body to x.go
	defer os.Remove(src)
	err := ioutil.WriteFile(src, []byte(body), 0666)
	if err != nil {
		return err
	}

	// build x.go, creating x
	p.bin = bin // to be removed by p.end
	dir, file := filepath.Split(src)
	args := []string{"go", "build", "-tags", "OMIT"}
	if opt != nil && opt.Race {
		p.out <- &Message{
			Id: p.id, Kind: "stderr",
			Body: "Running with race detector.\n",
		}
		args = append(args, "-race")
	}
	args = append(args, "-o", bin, file)
	cmd := p.cmd(dir, args...)
	cmd.Stdout = cmd.Stderr // send compiler output to stderr
	if err := cmd.Run(); err != nil {
		return err
	}

	// run x
	cmd = p.cmd("", bin)
	if opt != nil && opt.Race {
		cmd.Env = append(cmd.Env, "GOMAXPROCS=2")
	}
	if err := cmd.Start(); err != nil {
		// If we failed to exec, that might be because they built
		// a non-main package instead of an executable.
		// Check and report that.
		if name, err := packageName(body); err == nil && name != "main" {
			return errors.New(`executable programs must use "package main"`)
		}
		return err
	}
	p.run = cmd
	return nil
}

// wait waits for the running process to complete
// and sends its error state to the client.
func (p *process) wait() {
	p.end(p.run.Wait())
	close(p.done) // unblock waiting Kill calls
}

// end sends an "end" message to the client, containing the process id and the
// given error value. It also removes the binary.
func (p *process) end(err error) {
	if p.bin != "" {
		defer os.Remove(p.bin)
	}
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	// Wait for any outstanding reads to finish (potential race here).
	time.AfterFunc(msgDelay, func() { p.out <- m })
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// process' output channel.
func (p *process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Env = Environ()
	cmd.Stdout = &messageWriter{id: p.id, kind: "stdout", out: p.out}
	cmd.Stderr = &messageWriter{id: p.id, kind: "stderr", out: p.out}
	return cmd
}

func packageName(body string) (string, error) {
	f, err := parser.ParseFile(token.NewFileSet(), "prog.go",
		strings.NewReader(body), parser.PackageClauseOnly)
	if err != nil {
		return "", err
	}
	return f.Name.String(), nil
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message

	mu   sync.Mutex
	buf  []byte
	send *time.Timer
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	// Buffer writes that occur in a short period to send as one Message.
	w.mu.Lock()
	w.buf = append(w.buf, b...)
	if w.send == nil {
		w.send = time.AfterFunc(msgDelay, w.sendNow)
	}
	w.mu.Unlock()
	return len(b), nil
}

func (w *messageWriter) sendNow() {
	w.mu.Lock()
	body := safeString(w.buf)
	w.buf, w.send = nil, nil
	w.mu.Unlock()
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: body}
}

// safeString returns b as a valid UTF-8 string.
func safeString(b []byte) string {
	if utf8.Valid(b) {
		return string(b)
	}
	var buf bytes.Buffer
	for len(b) > 0 {
		r, size := utf8.DecodeRune(b)
		b = b[size:]
		buf.WriteRune(r)
	}
	return buf.String()
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}
<commit_msg>go.tools/playground: provide script-safe option for playground<commit_after>// Copyright 2012 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.

// +build !appengine

// Package socket implements an WebSocket-based playground backend.
// Clients connect to a websocket handler and send run/kill commands, and
// the server sends the output and exit status of the running processes.
// Multiple clients running multiple processes may be served concurrently.
// The wire format is JSON and is described by the Message type.
//
// This will not run on App Engine as WebSockets are not supported there.
package socket

import (
	"bytes"
	"encoding/json"
	"errors"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"code.google.com/p/go.net/websocket"
)

// RunScripts specifies whether the socket handler should execute shell scripts
// (snippets that start with a shebang).
var RunScripts = true

// Handler implements a WebSocket handler for a client connection.
var Handler = websocket.Handler(socketHandler)

// Environ provides an environment when a binary, such as the go tool, is
// invoked.
var Environ func() []string = os.Environ

const (
	// The maximum number of messages to send per session (avoid flooding).
	msgLimit = 1000

	// Batch messages sent in this interval and send as a single message.
	msgDelay = 10 * time.Millisecond
)

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id      string // client-provided unique id for the process
	Kind    string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body    string
	Options *Options `json:",omitempty"`
}

// Options specify additional message options.
type Options struct {
	Race bool // use -race flag when building code (for "run" only)
}

// socketHandler handles the websocket connection for a given present session.
// It handles transcoding Messages to and from JSON format, and starting
// and killing processes.
func socketHandler(c *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and send to the in channel.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Start and kill processes and handle errors.
	proc := make(map[string]*process)
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = startProcess(m.Id, m.Body, lOut, m.Options)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			if err != io.EOF {
				// A encode or decode has failed; bail.
				log.Println(err)
			}
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// process represents a running process.
type process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
	bin  string
}

// startProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func startProcess(id, body string, out chan<- *Message, opt *Options) *process {
	p := &process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	var err error
	if path, args := shebang(body); RunScripts && path != "" {
		err = p.startProcess(path, args, body)
	} else {
		err = p.start(body, opt)
	}
	if err != nil {
		p.end(err)
		return nil
	}
	go p.wait()
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *process) Kill() {
	if p == nil {
		return
	}
	p.run.Process.Kill()
	<-p.done // block until process exits
}

// shebang looks for a shebang ('#!') at the beginning of the passed string.
// If found, it returns the path and args after the shebang.
// args includes the command as args[0].
func shebang(body string) (path string, args []string) {
	body = strings.TrimSpace(body)
	if !strings.HasPrefix(body, "#!") {
		return "", nil
	}
	if i := strings.Index(body, "\n"); i >= 0 {
		body = body[:i]
	}
	fs := strings.Fields(body[2:])
	return fs[0], fs
}

// startProcess starts a given program given its path and passing the given body
// to the command standard input.
func (p *process) startProcess(path string, args []string, body string) error {
	cmd := &exec.Cmd{
		Path:   path,
		Args:   args,
		Stdin:  strings.NewReader(body),
		Stdout: &messageWriter{id: p.id, kind: "stdout", out: p.out},
		Stderr: &messageWriter{id: p.id, kind: "stderr", out: p.out},
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	p.run = cmd
	return nil
}

// start builds and starts the given program, sending its output to p.out,
// and stores the running *exec.Cmd in the run field.
func (p *process) start(body string, opt *Options) error {
	// We "go build" and then exec the binary so that the
	// resultant *exec.Cmd is a handle to the user's program
	// (rather than the go tool process).
	// This makes Kill work.

	bin := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := bin + ".go"
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write body to x.go
	defer os.Remove(src)
	err := ioutil.WriteFile(src, []byte(body), 0666)
	if err != nil {
		return err
	}

	// build x.go, creating x
	p.bin = bin // to be removed by p.end
	dir, file := filepath.Split(src)
	args := []string{"go", "build", "-tags", "OMIT"}
	if opt != nil && opt.Race {
		p.out <- &Message{
			Id: p.id, Kind: "stderr",
			Body: "Running with race detector.\n",
		}
		args = append(args, "-race")
	}
	args = append(args, "-o", bin, file)
	cmd := p.cmd(dir, args...)
	cmd.Stdout = cmd.Stderr // send compiler output to stderr
	if err := cmd.Run(); err != nil {
		return err
	}

	// run x
	cmd = p.cmd("", bin)
	if opt != nil && opt.Race {
		cmd.Env = append(cmd.Env, "GOMAXPROCS=2")
	}
	if err := cmd.Start(); err != nil {
		// If we failed to exec, that might be because they built
		// a non-main package instead of an executable.
		// Check and report that.
		if name, err := packageName(body); err == nil && name != "main" {
			return errors.New(`executable programs must use "package main"`)
		}
		return err
	}
	p.run = cmd
	return nil
}

// wait waits for the running process to complete
// and sends its error state to the client.
func (p *process) wait() {
	p.end(p.run.Wait())
	close(p.done) // unblock waiting Kill calls
}

// end sends an "end" message to the client, containing the process id and the
// given error value. It also removes the binary.
func (p *process) end(err error) {
	if p.bin != "" {
		defer os.Remove(p.bin)
	}
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	// Wait for any outstanding reads to finish (potential race here).
	time.AfterFunc(msgDelay, func() { p.out <- m })
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// process' output channel.
func (p *process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Env = Environ()
	cmd.Stdout = &messageWriter{id: p.id, kind: "stdout", out: p.out}
	cmd.Stderr = &messageWriter{id: p.id, kind: "stderr", out: p.out}
	return cmd
}

func packageName(body string) (string, error) {
	f, err := parser.ParseFile(token.NewFileSet(), "prog.go",
		strings.NewReader(body), parser.PackageClauseOnly)
	if err != nil {
		return "", err
	}
	return f.Name.String(), nil
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message

	mu   sync.Mutex
	buf  []byte
	send *time.Timer
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	// Buffer writes that occur in a short period to send as one Message.
	w.mu.Lock()
	w.buf = append(w.buf, b...)
	if w.send == nil {
		w.send = time.AfterFunc(msgDelay, w.sendNow)
	}
	w.mu.Unlock()
	return len(b), nil
}

func (w *messageWriter) sendNow() {
	w.mu.Lock()
	body := safeString(w.buf)
	w.buf, w.send = nil, nil
	w.mu.Unlock()
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: body}
}

// safeString returns b as a valid UTF-8 string.
func safeString(b []byte) string {
	if utf8.Valid(b) {
		return string(b)
	}
	var buf bytes.Buffer
	for len(b) > 0 {
		r, size := utf8.DecodeRune(b)
		b = b[size:]
		buf.WriteRune(r)
	}
	return buf.String()
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"code.google.com/p/log4go"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime/backend"
	"github.com/limetext/lime/backend/render"
	"os"
	"path"
	"time"
)

func sublime_Console(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	if tu.Size() != 1 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		log4go.Info("Python sez: %s", i)
	}
	return toPython(nil)
}

func sublime_set_timeout(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	var (
		pyarg py.Object
	)
	if tu.Size() != 2 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		pyarg = i
	}
	if i, err := tu.GetItem(1); err != nil {
		return nil, err
	} else if v, err := fromPython(i); err != nil {
		return nil, err
	} else if v2, ok := v.(int); !ok {
		return nil, fmt.Errorf("Expected int not %s", i.Type())
	} else {
		pyarg.Incref()
		go func() {
			time.Sleep(time.Millisecond * time.Duration(v2))
			l := py.NewLock()
			defer l.Unlock()
			defer pyarg.Decref()
			if ret, err := pyarg.Base().CallFunctionObjArgs(); err != nil {
				log4go.Debug("Error in callback: %v", err)
			} else {
				ret.Decref()
			}
		}()
	}
	return toPython(nil)
}

func init() {
	sublime_methods = append(sublime_methods, py.Method{Name: "console", Func: sublime_Console}, py.Method{Name: "set_timeout", Func: sublime_set_timeout})
	backend.GetEditor()
	l := py.InitAndLock()
	defer l.Unlock()
	//	py.InitializeEx(false)
	m, err := py.InitModule("sublime", sublime_methods)
	if err != nil {
		panic(err)
	}

	type class struct {
		name string
		c    *py.Class
	}
	classes := []class{
		{"Region", &_regionClass},
		{"RegionSet", &_region_setClass},
		{"View", &_viewClass},
		{"Window", &_windowClass},
		{"Edit", &_editClass},
		{"Settings", &_settingsClass},
		{"WindowCommandGlue", &_windowCommandGlueClass},
		{"TextCommandGlue", &_textCommandGlueClass},
		{"ApplicationCommandGlue", &_applicationCommandGlueClass},
		{"OnQueryContextGlue", &_onQueryContextGlueClass},
		{"ViewEventGlue", &_viewEventGlueClass},
	}
	type constant struct {
		name     string
		constant int
	}
	constants := []constant{
		{"OP_EQUAL", int(backend.OpEqual)},
		{"OP_NOT_EQUAL", int(backend.OpNotEqual)},
		{"OP_REGEX_MATCH", int(backend.OpRegexMatch)},
		{"OP_NOT_REGEX_MATCH", int(backend.OpNotRegexMatch)},
		{"OP_REGEX_CONTAINS", int(backend.OpRegexContains)},
		{"OP_NOT_REGEX_CONTAINS", int(backend.OpNotRegexContains)},
		{"INHIBIT_WORD_COMPLETIONS", 0},
		{"INHIBIT_EXPLICIT_COMPLETIONS", 0},
		{"LITERAL", 0},
		{"IGNORECASE", 0},
		{"CLASS_WORD_START", 1},
		{"CLASS_WORD_END", 2},
		{"CLASS_PUNCTUATION_START", 4},
		{"CLASS_PUNCTUATION_END", 8},
		{"CLASS_SUB_WORD_START", 16},
		{"CLASS_SUB_WORD_END", 32},
		{"CLASS_LINE_START", 64},
		{"CLASS_LINE_END", 128},
		{"CLASS_EMPTY_LINE", 256},
		{"CLASS_MIDDLE_WORD", 512},
		{"CLASS_WORD_START_WITH_PUNCTUATION", 1024},
		{"CLASS_WORD_END_WITH_PUNCTUATION", 2048},
		{"CLASS_OPENING_PARENTHESIS", 4096},
		{"CLASS_CLOSING_PARENTHESIS", 8192},
		{"DRAW_EMPTY", int(render.DRAW_EMPTY)},
		{"HIDE_ON_MINIMAP", int(render.HIDE_ON_MINIMAP)},
		{"DRAW_EMPTY_AS_OVERWRITE", int(render.DRAW_EMPTY_AS_OVERWRITE)},
		{"DRAW_NO_FILL", int(render.DRAW_NO_FILL)},
		{"DRAW_NO_OUTLINE", int(render.DRAW_NO_OUTLINE)},
		{"DRAW_SOLID_UNDERLINE", int(render.DRAW_SOLID_UNDERLINE)},
		{"DRAW_STIPPLED_UNDERLINE", int(render.DRAW_STIPPLED_UNDERLINE)},
		{"DRAW_SQUIGGLY_UNDERLINE", int(render.DRAW_SQUIGGLY_UNDERLINE)},
		{"PERSISTENT", int(render.PERSISTENT)},
		{"HIDDEN", int(render.HIDDEN)},
	}

	for _, cl := range classes {
		c, err := cl.c.Create()
		if err != nil {
			panic(err)
		}
		if err := m.AddObject(cl.name, c); err != nil {
			panic(err)
		}
	}
	for _, c := range constants {
		if err := m.AddIntConstant(c.name, c.constant); err != nil {
			panic(err)
		}
	}
	py.AddToPath(backend.LIME_PACKAGES_PATH)
	py.AddToPath(backend.LIME_USER_PACKAGES_PATH)
	py.AddToPath(path.Join("..", "..", "backend", "sublime"))
}

func loadPlugin(p *backend.Plugin, m *py.Module) {
	fi := p.Get().([]os.FileInfo)
	for _, f := range fi {
		fn := f.Name()
		s, err := py.NewUnicode(path.Base(p.Name()) + "." + fn[:len(fn)-3])
		if err != nil {
			log4go.Error(err)
			return
		}
		if r, err := m.Base().CallMethodObjArgs("reload_plugin", s); err != nil {
			log4go.Error(err)
		} else if r != nil {
			r.Decref()
		}
	}
	p.LoadPackets()
	watch(backend.NewWatchedPackage(p))
}

var (
	watcher        *fsnotify.Watcher
	watchedPlugins map[string]*backend.WatchedPackage
)

func watch(plugin *backend.WatchedPackage) {
	log4go.Finest("Watch(%v)", plugin)
	if err := watcher.Watch(plugin.Name()); err != nil {
		log4go.Error("Could not watch plugin: %v", err)
	} else {
		watchedPlugins[plugin.Name()] = plugin
	}
}

func unWatch(name string) {
	if err := watcher.RemoveWatch(name); err != nil {
		log4go.Error("Couldn't unwatch file: %v", err)
	}
	log4go.Finest("UnWatch(%s)", name)
	delete(watchedPlugins, name)
}

func observePlugins(m *py.Module) {
	for {
		select {
		case ev := <-watcher.Event:
			if ev.IsModify() {
				if p, exist := watchedPlugins[path.Dir(ev.Name)]; exist {
					p.Reload()
					loadPlugin(p.Package().(*backend.Plugin), m)
				}
			}
		case err := <-watcher.Error:
			log4go.Error("error:", err)
		}
	}
}

// TODO
func Init() {
	l := py.NewLock()
	defer l.Unlock()
	m, err := py.Import("sublime_plugin")
	if err != nil {
		panic(err)
	}
	sys, err := py.Import("sys")
	if err != nil {
		log4go.Debug(err)
	} else {
		defer sys.Decref()
	}

	watcher, err = fsnotify.NewWatcher()
	if err != nil {
		log4go.Error("Could not create watcher due to: %v", err)
	}
	watchedPlugins = make(map[string]*backend.WatchedPackage)
	go observePlugins(m)

	plugins := backend.ScanPlugins(backend.LIME_USER_PACKAGES_PATH, ".py")
	for _, p := range plugins {
		// TODO: add all plugins after supporting all commands
		if p.Name() == path.Join("..", "..", "3rdparty", "bundles", "Vintageous") {
			loadPlugin(p, m)
		}
	}
}
<commit_msg>backend/sublime: Also reload plugins on the Create fs event.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"code.google.com/p/log4go"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime/backend"
	"github.com/limetext/lime/backend/render"
	"os"
	"path"
	"time"
)

func sublime_Console(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	if tu.Size() != 1 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		log4go.Info("Python sez: %s", i)
	}
	return toPython(nil)
}

func sublime_set_timeout(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	var (
		pyarg py.Object
	)
	if tu.Size() != 2 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		pyarg = i
	}
	if i, err := tu.GetItem(1); err != nil {
		return nil, err
	} else if v, err := fromPython(i); err != nil {
		return nil, err
	} else if v2, ok := v.(int); !ok {
		return nil, fmt.Errorf("Expected int not %s", i.Type())
	} else {
		pyarg.Incref()
		go func() {
			time.Sleep(time.Millisecond * time.Duration(v2))
			l := py.NewLock()
			defer l.Unlock()
			defer pyarg.Decref()
			if ret, err := pyarg.Base().CallFunctionObjArgs(); err != nil {
				log4go.Debug("Error in callback: %v", err)
			} else {
				ret.Decref()
			}
		}()
	}
	return toPython(nil)
}

func init() {
	sublime_methods = append(sublime_methods, py.Method{Name: "console", Func: sublime_Console}, py.Method{Name: "set_timeout", Func: sublime_set_timeout})
	backend.GetEditor()
	l := py.InitAndLock()
	defer l.Unlock()
	//	py.InitializeEx(false)
	m, err := py.InitModule("sublime", sublime_methods)
	if err != nil {
		panic(err)
	}

	type class struct {
		name string
		c    *py.Class
	}
	classes := []class{
		{"Region", &_regionClass},
		{"RegionSet", &_region_setClass},
		{"View", &_viewClass},
		{"Window", &_windowClass},
		{"Edit", &_editClass},
		{"Settings", &_settingsClass},
		{"WindowCommandGlue", &_windowCommandGlueClass},
		{"TextCommandGlue", &_textCommandGlueClass},
		{"ApplicationCommandGlue", &_applicationCommandGlueClass},
		{"OnQueryContextGlue", &_onQueryContextGlueClass},
		{"ViewEventGlue", &_viewEventGlueClass},
	}
	type constant struct {
		name     string
		constant int
	}
	constants := []constant{
		{"OP_EQUAL", int(backend.OpEqual)},
		{"OP_NOT_EQUAL", int(backend.OpNotEqual)},
		{"OP_REGEX_MATCH", int(backend.OpRegexMatch)},
		{"OP_NOT_REGEX_MATCH", int(backend.OpNotRegexMatch)},
		{"OP_REGEX_CONTAINS", int(backend.OpRegexContains)},
		{"OP_NOT_REGEX_CONTAINS", int(backend.OpNotRegexContains)},
		{"INHIBIT_WORD_COMPLETIONS", 0},
		{"INHIBIT_EXPLICIT_COMPLETIONS", 0},
		{"LITERAL", 0},
		{"IGNORECASE", 0},
		{"CLASS_WORD_START", 1},
		{"CLASS_WORD_END", 2},
		{"CLASS_PUNCTUATION_START", 4},
		{"CLASS_PUNCTUATION_END", 8},
		{"CLASS_SUB_WORD_START", 16},
		{"CLASS_SUB_WORD_END", 32},
		{"CLASS_LINE_START", 64},
		{"CLASS_LINE_END", 128},
		{"CLASS_EMPTY_LINE", 256},
		{"CLASS_MIDDLE_WORD", 512},
		{"CLASS_WORD_START_WITH_PUNCTUATION", 1024},
		{"CLASS_WORD_END_WITH_PUNCTUATION", 2048},
		{"CLASS_OPENING_PARENTHESIS", 4096},
		{"CLASS_CLOSING_PARENTHESIS", 8192},
		{"DRAW_EMPTY", int(render.DRAW_EMPTY)},
		{"HIDE_ON_MINIMAP", int(render.HIDE_ON_MINIMAP)},
		{"DRAW_EMPTY_AS_OVERWRITE", int(render.DRAW_EMPTY_AS_OVERWRITE)},
		{"DRAW_NO_FILL", int(render.DRAW_NO_FILL)},
		{"DRAW_NO_OUTLINE", int(render.DRAW_NO_OUTLINE)},
		{"DRAW_SOLID_UNDERLINE", int(render.DRAW_SOLID_UNDERLINE)},
		{"DRAW_STIPPLED_UNDERLINE", int(render.DRAW_STIPPLED_UNDERLINE)},
		{"DRAW_SQUIGGLY_UNDERLINE", int(render.DRAW_SQUIGGLY_UNDERLINE)},
		{"PERSISTENT", int(render.PERSISTENT)},
		{"HIDDEN", int(render.HIDDEN)},
	}

	for _, cl := range classes {
		c, err := cl.c.Create()
		if err != nil {
			panic(err)
		}
		if err := m.AddObject(cl.name, c); err != nil {
			panic(err)
		}
	}
	for _, c := range constants {
		if err := m.AddIntConstant(c.name, c.constant); err != nil {
			panic(err)
		}
	}
	py.AddToPath(backend.LIME_PACKAGES_PATH)
	py.AddToPath(backend.LIME_USER_PACKAGES_PATH)
	py.AddToPath(path.Join("..", "..", "backend", "sublime"))
}

func loadPlugin(p *backend.Plugin, m *py.Module) {
	fi := p.Get().([]os.FileInfo)
	for _, f := range fi {
		fn := f.Name()
		s, err := py.NewUnicode(path.Base(p.Name()) + "." + fn[:len(fn)-3])
		if err != nil {
			log4go.Error(err)
			return
		}
		if r, err := m.Base().CallMethodObjArgs("reload_plugin", s); err != nil {
			log4go.Error(err)
		} else if r != nil {
			r.Decref()
		}
	}
	p.LoadPackets()
	watch(backend.NewWatchedPackage(p))
}

var (
	watcher        *fsnotify.Watcher
	watchedPlugins map[string]*backend.WatchedPackage
)

func watch(plugin *backend.WatchedPackage) {
	log4go.Finest("Watch(%v)", plugin)
	if err := watcher.Watch(plugin.Name()); err != nil {
		log4go.Error("Could not watch plugin: %v", err)
	} else {
		watchedPlugins[plugin.Name()] = plugin
	}
}

func unWatch(name string) {
	if err := watcher.RemoveWatch(name); err != nil {
		log4go.Error("Couldn't unwatch file: %v", err)
	}
	log4go.Finest("UnWatch(%s)", name)
	delete(watchedPlugins, name)
}

func observePlugins(m *py.Module) {
	for {
		select {
		case ev := <-watcher.Event:
			if !(ev.IsModify() || ev.IsCreate()) {
				continue
			}
			if p, exist := watchedPlugins[path.Dir(ev.Name)]; exist {
				p.Reload()
				loadPlugin(p.Package().(*backend.Plugin), m)
			}
		case err := <-watcher.Error:
			log4go.Error("error:", err)
		}
	}
}

// TODO
func Init() {
	l := py.NewLock()
	defer l.Unlock()
	m, err := py.Import("sublime_plugin")
	if err != nil {
		panic(err)
	}
	sys, err := py.Import("sys")
	if err != nil {
		log4go.Debug(err)
	} else {
		defer sys.Decref()
	}

	watcher, err = fsnotify.NewWatcher()
	if err != nil {
		log4go.Error("Could not create watcher due to: %v", err)
	}
	watchedPlugins = make(map[string]*backend.WatchedPackage)
	go observePlugins(m)

	plugins := backend.ScanPlugins(backend.LIME_USER_PACKAGES_PATH, ".py")
	for _, p := range plugins {
		// TODO: add all plugins after supporting all commands
		if p.Name() == path.Join("..", "..", "3rdparty", "bundles", "Vintageous") {
			loadPlugin(p, m)
		}
	}
}
<|endoftext|>


<commit_before>// replies when someone mentions the bot's name
package identity

import (
	"fmt"
	"github.com/sdstrowes/gesture/core"
)

func Create(bot *core.Gobot, config map[string]interface{}) {
	name := bot.Name

	bot.ListenFor(fmt.Sprintf("(?i)kill %s", name), func(msg core.Message, matches []string) core.Response {
		msg.Reply("EAT SHIT")
		return bot.Stop()
	})

	bot.ListenFor(fmt.Sprintf("(?i)(hey|h(a?)i|hello) %s", name), func(msg core.Message, matches []string) core.Response {
		msg.Send(fmt.Sprintf("why, hello there %s", msg.User))
		return bot.Stop()
	})
}
<commit_msg>add a festive message<commit_after>// replies when someone mentions the bot's name
package identity

import (
	"fmt"
	"github.com/sdstrowes/gesture/core"
)

func Create(bot *core.Gobot, config map[string]interface{}) {
	name := bot.Name

	bot.ListenFor(fmt.Sprintf("(?i)kill %s", name), func(msg core.Message, matches []string) core.Response {
		msg.Reply("EAT SHIT")
		return bot.Stop()
	})

	bot.ListenFor(fmt.Sprintf("(?i)(hey|h(a?)i|hello) %s", name), func(msg core.Message, matches []string) core.Response {
		msg.Send(fmt.Sprintf("why, hello there %s", msg.User))
		return bot.Stop()
	})

	bot.ListenFor(fmt.Sprintf("(?i)(H|h)appy new year(!*|,)) %s", name), func(msg core.Message, matches []string) core.Response {
		msg.Send(fmt.Sprintf("why, hello there %s", msg.User))
		return bot.Stop()
	})
}

<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package discoverspaces

import (
	"github.com/juju/errors"
	"github.com/juju/juju/api/discoverspaces"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/worker"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"launchpad.net/tomb"
)

var logger = loggo.GetLogger("juju.discoverspaces")

type discoverspacesWorker struct {
	api      *discoverspaces.API
	tomb     tomb.Tomb
	observer *worker.EnvironObserver
}

// NewWorker returns a worker
func NewWorker(api *discoverspaces.API) worker.Worker {
	dw := &discoverspacesWorker{
		api: api,
	}
	go func() {
		defer dw.tomb.Done()
		dw.tomb.Kill(dw.loop())
	}()
	return dw
}

func (dw *discoverspacesWorker) Kill() {
	dw.tomb.Kill(nil)
}

func (dw *discoverspacesWorker) Wait() error {
	return dw.tomb.Wait()
}

func (dw *discoverspacesWorker) loop() (err error) {
	dw.observer, err = worker.NewEnvironObserver(dw.api)
	if err != nil {
		return err
	}
	defer func() {
		obsErr := worker.Stop(dw.observer)
		if err == nil {
			err = obsErr
		}
	}()
	environ := dw.observer.Environ()
	networkingEnviron, ok := environs.SupportsNetworking(environ)

	if ok {
		err = dw.handleSubnets(networkingEnviron)
		if err != nil {
			return errors.Trace(err)
		}
	}

	// TODO(mfoord): we'll have a watcher here checking if we need to
	// update the spaces/subnets definition.
	for {
	}
	return err
}

func (dw *discoverspacesWorker) handleSubnets(env environs.NetworkingEnviron) error {
	ok, err := env.SupportsSpaceDiscovery()
	if err != nil {
		return errors.Trace(err)
	}
	if !ok {
		// Nothing to do.
		return nil
	}
	providerSpaces, err := env.Spaces()
	if err != nil {
		return errors.Trace(err)
	}
	listSpacesResult, err := dw.api.ListSpaces()
	if err != nil {
		return errors.Trace(err)
	}
	stateSpaceMap := make(map[string]params.ProviderSpace)
	for _, space := range listSpacesResult.Results {
		stateSpaceMap[space.ProviderId] = space
	}

	// TODO(mfoord): we also need to attempt to delete spaces that no
	// longer exist, so long as they're not in use.
	for _, space := range providerSpaces {
		_, ok := stateSpaceMap[space.Name]
		if !ok {
			// We need to create the space.
			// XXX in the apiserver the name should be generated and
			// IsPublic set to false.
			args := params.CreateSpacesParams{}
			_, err := dw.api.CreateSpaces(args)
			if err != nil {
				return errors.Trace(err)
			}
		}
		// TODO(mfoord): currently no way of removing subnets, or
		// changing the space they're in, so we can only add ones we
		// don't already know about.
		for _, subnet := range space.Subnets {
			spaceTag, err := names.ParseSpaceTag(space.Name)
			if err != nil {
				return errors.Trace(err)
			}
			subnetTag, err := names.ParseSubnetTag(subnet.CIDR)
			if err != nil {
				return errors.Trace(err)
			}

			args := params.AddSubnetsParams{
				Subnets: []params.AddSubnetParams{{
					SubnetTag:        subnetTag.String(),
					SubnetProviderId: string(subnet.ProviderId),
					SpaceTag:         spaceTag.String(),
					Zones:            subnet.AvailabilityZones,
				}}}
			_, err = dw.api.AddSubnets(args)
			if err != nil {
				return errors.Trace(err)
			}
		}
	}
	return nil
}
<commit_msg>Listen for dying<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package discoverspaces

import (
	"github.com/juju/errors"
	"github.com/juju/juju/api/discoverspaces"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/worker"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"launchpad.net/tomb"
)

var logger = loggo.GetLogger("juju.discoverspaces")

type discoverspacesWorker struct {
	api      *discoverspaces.API
	tomb     tomb.Tomb
	observer *worker.EnvironObserver
}

// NewWorker returns a worker
func NewWorker(api *discoverspaces.API) worker.Worker {
	dw := &discoverspacesWorker{
		api: api,
	}
	go func() {
		defer dw.tomb.Done()
		dw.tomb.Kill(dw.loop())
	}()
	return dw
}

func (dw *discoverspacesWorker) Kill() {
	dw.tomb.Kill(nil)
}

func (dw *discoverspacesWorker) Wait() error {
	return dw.tomb.Wait()
}

func (dw *discoverspacesWorker) loop() (err error) {
	dw.observer, err = worker.NewEnvironObserver(dw.api)
	if err != nil {
		return err
	}
	defer func() {
		obsErr := worker.Stop(dw.observer)
		if err == nil {
			err = obsErr
		}
	}()
	environ := dw.observer.Environ()
	networkingEnviron, ok := environs.SupportsNetworking(environ)

	if ok {
		err = dw.handleSubnets(networkingEnviron)
		if err != nil {
			return errors.Trace(err)
		}
	}

	// TODO(mfoord): we'll have a watcher here checking if we need to
	// update the spaces/subnets definition.
	dying := u.tomb.Dying()
	for {
		select {
		case <-dying:
			return nil
		}
	}
	return nil
}

func (dw *discoverspacesWorker) handleSubnets(env environs.NetworkingEnviron) error {
	ok, err := env.SupportsSpaceDiscovery()
	if err != nil {
		return errors.Trace(err)
	}
	if !ok {
		// Nothing to do.
		return nil
	}
	providerSpaces, err := env.Spaces()
	if err != nil {
		return errors.Trace(err)
	}
	listSpacesResult, err := dw.api.ListSpaces()
	if err != nil {
		return errors.Trace(err)
	}
	stateSpaceMap := make(map[string]params.ProviderSpace)
	for _, space := range listSpacesResult.Results {
		stateSpaceMap[space.ProviderId] = space
	}

	// TODO(mfoord): we also need to attempt to delete spaces and subnets
	// that no longer exist, so long as they're not in use.
	for _, space := range providerSpaces {
		_, ok := stateSpaceMap[space.Name]
		if !ok {
			// We need to create the space.
			// XXX in the apiserver the name should be generated and
			// IsPublic set to false.
			args := params.CreateSpacesParams{}
			_, err := dw.api.CreateSpaces(args)
			if err != nil {
				return errors.Trace(err)
			}
		}
		// TODO(mfoord): currently no way of removing subnets, or
		// changing the space they're in, so we can only add ones we
		// don't already know about.
		for _, subnet := range space.Subnets {
			spaceTag, err := names.ParseSpaceTag(space.Name)
			if err != nil {
				return errors.Trace(err)
			}
			subnetTag, err := names.ParseSubnetTag(subnet.CIDR)
			if err != nil {
				return errors.Trace(err)
			}

			args := params.AddSubnetsParams{
				Subnets: []params.AddSubnetParams{{
					SubnetTag:        subnetTag.String(),
					SubnetProviderId: string(subnet.ProviderId),
					SpaceTag:         spaceTag.String(),
					Zones:            subnet.AvailabilityZones,
				}}}
			_, err = dw.api.AddSubnets(args)
			if err != nil {
				return errors.Trace(err)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package instancepoller

import (
        "fmt"

	gc "launchpad.net/gocheck"

        "launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/testing/testbase"
)

type aggregateSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&aggregateSuite{})

type testInstance struct {
    instance.Instance
    addresses []instance.Address
    id instance.Id
    address instance.Address
}

func (t *testInstance) Addresses() ([]instance.Address, error) {
    return t.addresses, nil
}

func (t *testInstance) Id() (instance.Id) {
    return t.id
}

type testInstanceGetter struct {
    ids []instance.Id
    results []instanceInfoReply
}

func (i *testInstanceGetter) Instances(ids []instance.Id) ([]instance.Instance, error) {
//    var results []instance.Instance
//    results[0] = testInstance{}
    i.ids = ids
    return nil, fmt.Errorf("Some error")
}

func (s *aggregateSuite) TestLoop(c *gc.C) {
    testGetter := new(testInstanceGetter)
    aggregator := newAggregator(testGetter)

    replyChan := make(chan instanceInfoReply)
    req := instanceInfoReq{
        reply: replyChan,
        instId: instance.Id("foo"),
    }
    aggregator.reqc <- req
    reply :=  <-replyChan
    c.Assert(reply.info, gc.Equals, instanceInfo{})
    c.Assert(testGetter.ids, gc.Equals, []instance.Id{instance.Id("foo")})
}
<commit_msg>testInstanceGetter can now return results or an error<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package instancepoller

import (
        "fmt"

	gc "launchpad.net/gocheck"

        "launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/testing/testbase"
)

type aggregateSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&aggregateSuite{})

type testInstance struct {
    instance.Instance
    addresses []instance.Address
    id instance.Id
    address instance.Address
}

func (t *testInstance) Addresses() ([]instance.Address, error) {
    return t.addresses, nil
}

func (t *testInstance) Id() (instance.Id) {
    return t.id
}

type testInstanceGetter struct {
    ids []instance.Id
    results []instance.Instance
    err bool
}

func (i *testInstanceGetter) Instances(ids []instance.Id) ([]instance.Instance, error) {
    i.ids = ids
    if i.err {
        return nil, fmt.Errorf("Some error")
    }
    return i.results, nil
}

func (s *aggregateSuite) TestLoop(c *gc.C) {
    testGetter := new(testInstanceGetter)
    testGetter.err = true
    aggregator := newAggregator(testGetter)

    replyChan := make(chan instanceInfoReply)
    req := instanceInfoReq{
        reply: replyChan,
        instId: instance.Id("foo"),
    }
    aggregator.reqc <- req
    reply :=  <-replyChan
    c.Assert(reply.info, gc.DeepEquals, instanceInfo{})
    c.Assert(testGetter.ids, gc.DeepEquals, []instance.Id{instance.Id("foo")})
}
<|endoftext|>