<commit_before>package php

import "stephensearles.com/php/ast"

func (p *parser) parseInstantiation() ast.Expression {
	p.expectCurrent(itemNewOperator)
	expr := &ast.NewExpression{}
	expr.Class = p.parseNextExpression()

	if p.peek().typ == itemOpenParen {
		p.expect(itemOpenParen)
		if p.peek().typ != itemCloseParen {
			expr.Arguments = append(expr.Arguments, p.parseNextExpression())
			for p.peek().typ == itemComma {
				p.expect(itemComma)
				expr.Arguments = append(expr.Arguments, p.parseNextExpression())
			}
		}
		p.expect(itemCloseParen)
	}
	return expr
}

func (p *parser) parseClass() ast.Class {
	if p.current.typ == itemAbstract {
		p.expect(itemClass)
	}
	p.expect(itemIdentifier)
	name := p.current.val
	if p.peek().typ == itemExtends {
		p.expect(itemExtends)
		p.expect(itemIdentifier)
	}
	if p.peek().typ == itemImplements {
		p.expect(itemImplements)
		p.expect(itemIdentifier)
		for p.peek().typ == itemComma {
			p.expect(itemComma)
			p.expect(itemIdentifier)
		}
	}
	p.expect(itemBlockBegin)
	return p.parseClassFields(ast.Class{Name: name})
}

func (p *parser) parseObjectLookup(r ast.Expression) (expr ast.Expression) {
	p.expectCurrent(itemObjectOperator)
	prop := &ast.PropertyExpression{
		Receiver: r,
	}
	switch p.next(); p.current.typ {
	case itemVariableOperator:
		prop.Name = p.parseExpression()
	case itemIdentifier:
		prop.Name = ast.Identifier{Value: p.current.val}
	}
	expr = prop
	switch pk := p.peek(); pk.typ {
	case itemOpenParen:
		expr = &ast.MethodCallExpression{
			Receiver:               r,
			FunctionCallExpression: p.parseFunctionCall(prop.Name),
		}
	}
	expr = p.parseOperation(p.parenLevel, expr)
	return
}

func (p *parser) parseVisibility() (vis ast.Visibility, found bool) {
	switch p.peek().typ {
	case itemPrivate:
		vis = ast.Private
	case itemPublic:
		vis = ast.Public
	case itemProtected:
		vis = ast.Protected
	default:
		return ast.Public, false
	}
	p.next()
	return vis, true
}

func (p *parser) parseAbstract() bool {
	if p.peek().typ == itemAbstract {
		p.next()
		return true
	}
	return false
}

func (p *parser) parseClassFields(c ast.Class) ast.Class {
	c.Methods = make([]ast.Method, 0)
	c.Properties = make([]ast.Property, 0)
	for p.peek().typ != itemBlockEnd {
		vis, _, _, abstract := p.parseClassMemberSettings()
		p.next()
		switch p.current.typ {
		case itemFunction:
			if abstract {
				f := p.parseFunctionDefinition()
				m := ast.Method{
					Visibility:   vis,
					FunctionStmt: &ast.FunctionStmt{FunctionDefinition: f},
				}
				c.Methods = append(c.Methods, m)
				p.expect(itemStatementEnd)
			} else {
				c.Methods = append(c.Methods, ast.Method{
					Visibility:   vis,
					FunctionStmt: p.parseFunctionStmt(),
				})
			}
		case itemVariableOperator:
			p.next()
			prop := ast.Property{
				Visibility: vis,
				Name:       "$" + p.current.val,
			}
			if p.peek().typ == itemAssignmentOperator {
				p.expect(itemAssignmentOperator)
				prop.Initialization = p.parseNextExpression()
			}
			c.Properties = append(c.Properties, prop)
			p.expect(itemStatementEnd)
		case itemConst:
			constant := ast.Constant{}
			p.expect(itemIdentifier)
			constant.Variable = ast.NewVariable(p.current.val)
			if p.peek().typ == itemAssignmentOperator {
				p.expect(itemAssignmentOperator)
				constant.Value = p.parseNextExpression()
			}
			c.Constants = append(c.Constants, constant)
			p.expect(itemStatementEnd)
		default:
			p.errorf("unexpected class member %v", p.current)
		}
	}
	p.expect(itemBlockEnd)
	return c
}

func (p *parser) parseInterface() *ast.Interface {
	i := &ast.Interface{
		Inherits: make([]string, 0),
	}
	p.expect(itemIdentifier)
	i.Name = p.current.val
	if p.peek().typ == itemExtends {
		p.expect(itemExtends)
		for {
			p.expect(itemIdentifier)
			i.Inherits = append(i.Inherits, p.current.val)
			if p.peek().typ != itemComma {
				break
			}
			p.expect(itemComma)
		}
	}
	p.expect(itemBlockBegin)
	for p.peek().typ != itemBlockEnd {
		vis, _ := p.parseVisibility()
		if p.peek().typ == itemStatic {
			p.next()
		}
		p.next()
		switch p.current.typ {
		case itemFunction:
			f := p.parseFunctionDefinition()
			m := ast.Method{
				Visibility:   vis,
				FunctionStmt: &ast.FunctionStmt{FunctionDefinition: f},
			}
			i.Methods = append(i.Methods, m)
			p.expect(itemStatementEnd)
		default:
			p.errorf("unexpected interface member %v", p.current)
		}
	}
	p.expect(itemBlockEnd)
	return i
}

func (p *parser) parseClassMemberSettings() (vis ast.Visibility, static, final, abstract bool) {
	var foundVis bool
	vis = ast.Public
	for {
		switch p.peek().typ {
		case itemAbstract:
			if abstract {
				p.errorf("found multiple abstract declarations")
			}
			abstract = true
			p.next()
		case itemPrivate, itemPublic, itemProtected:
			if foundVis {
				p.errorf("found multiple visibility declarations")
			}
			vis, foundVis = p.parseVisibility()
		case itemFinal:
			if final {
				p.errorf("found multiple final declarations")
			}
			final = true
			p.next()
		case itemStatic:
			if static {
				p.errorf("found multiple static declarations")
			}
			static = true
			p.next()
		default:
			return
		}
	}
	return
}
<commit_msg>Supporting object lookups wrapped in braces<commit_after>package php

import "stephensearles.com/php/ast"

func (p *parser) parseInstantiation() ast.Expression {
	p.expectCurrent(itemNewOperator)
	expr := &ast.NewExpression{}
	expr.Class = p.parseNextExpression()

	if p.peek().typ == itemOpenParen {
		p.expect(itemOpenParen)
		if p.peek().typ != itemCloseParen {
			expr.Arguments = append(expr.Arguments, p.parseNextExpression())
			for p.peek().typ == itemComma {
				p.expect(itemComma)
				expr.Arguments = append(expr.Arguments, p.parseNextExpression())
			}
		}
		p.expect(itemCloseParen)
	}
	return expr
}

func (p *parser) parseClass() ast.Class {
	if p.current.typ == itemAbstract {
		p.expect(itemClass)
	}
	p.expect(itemIdentifier)
	name := p.current.val
	if p.peek().typ == itemExtends {
		p.expect(itemExtends)
		p.expect(itemIdentifier)
	}
	if p.peek().typ == itemImplements {
		p.expect(itemImplements)
		p.expect(itemIdentifier)
		for p.peek().typ == itemComma {
			p.expect(itemComma)
			p.expect(itemIdentifier)
		}
	}
	p.expect(itemBlockBegin)
	return p.parseClassFields(ast.Class{Name: name})
}

func (p *parser) parseObjectLookup(r ast.Expression) (expr ast.Expression) {
	p.expectCurrent(itemObjectOperator)
	prop := &ast.PropertyExpression{
		Receiver: r,
	}
	switch p.next(); p.current.typ {
	case itemBlockBegin:
		prop.Name = p.parseNextExpression()
		p.expect(itemBlockEnd)
	case itemVariableOperator:
		prop.Name = p.parseExpression()
	case itemIdentifier:
		prop.Name = ast.Identifier{Value: p.current.val}
	}
	expr = prop
	switch pk := p.peek(); pk.typ {
	case itemOpenParen:
		expr = &ast.MethodCallExpression{
			Receiver:               r,
			FunctionCallExpression: p.parseFunctionCall(prop.Name),
		}
	}
	expr = p.parseOperation(p.parenLevel, expr)
	return
}

func (p *parser) parseVisibility() (vis ast.Visibility, found bool) {
	switch p.peek().typ {
	case itemPrivate:
		vis = ast.Private
	case itemPublic:
		vis = ast.Public
	case itemProtected:
		vis = ast.Protected
	default:
		return ast.Public, false
	}
	p.next()
	return vis, true
}

func (p *parser) parseAbstract() bool {
	if p.peek().typ == itemAbstract {
		p.next()
		return true
	}
	return false
}

func (p *parser) parseClassFields(c ast.Class) ast.Class {
	c.Methods = make([]ast.Method, 0)
	c.Properties = make([]ast.Property, 0)
	for p.peek().typ != itemBlockEnd {
		vis, _, _, abstract := p.parseClassMemberSettings()
		p.next()
		switch p.current.typ {
		case itemFunction:
			if abstract {
				f := p.parseFunctionDefinition()
				m := ast.Method{
					Visibility:   vis,
					FunctionStmt: &ast.FunctionStmt{FunctionDefinition: f},
				}
				c.Methods = append(c.Methods, m)
				p.expect(itemStatementEnd)
			} else {
				c.Methods = append(c.Methods, ast.Method{
					Visibility:   vis,
					FunctionStmt: p.parseFunctionStmt(),
				})
			}
		case itemVariableOperator:
			p.next()
			prop := ast.Property{
				Visibility: vis,
				Name:       "$" + p.current.val,
			}
			if p.peek().typ == itemAssignmentOperator {
				p.expect(itemAssignmentOperator)
				prop.Initialization = p.parseNextExpression()
			}
			c.Properties = append(c.Properties, prop)
			p.expect(itemStatementEnd)
		case itemConst:
			constant := ast.Constant{}
			p.expect(itemIdentifier)
			constant.Variable = ast.NewVariable(p.current.val)
			if p.peek().typ == itemAssignmentOperator {
				p.expect(itemAssignmentOperator)
				constant.Value = p.parseNextExpression()
			}
			c.Constants = append(c.Constants, constant)
			p.expect(itemStatementEnd)
		default:
			p.errorf("unexpected class member %v", p.current)
		}
	}
	p.expect(itemBlockEnd)
	return c
}

func (p *parser) parseInterface() *ast.Interface {
	i := &ast.Interface{
		Inherits: make([]string, 0),
	}
	p.expect(itemIdentifier)
	i.Name = p.current.val
	if p.peek().typ == itemExtends {
		p.expect(itemExtends)
		for {
			p.expect(itemIdentifier)
			i.Inherits = append(i.Inherits, p.current.val)
			if p.peek().typ != itemComma {
				break
			}
			p.expect(itemComma)
		}
	}
	p.expect(itemBlockBegin)
	for p.peek().typ != itemBlockEnd {
		vis, _ := p.parseVisibility()
		if p.peek().typ == itemStatic {
			p.next()
		}
		p.next()
		switch p.current.typ {
		case itemFunction:
			f := p.parseFunctionDefinition()
			m := ast.Method{
				Visibility:   vis,
				FunctionStmt: &ast.FunctionStmt{FunctionDefinition: f},
			}
			i.Methods = append(i.Methods, m)
			p.expect(itemStatementEnd)
		default:
			p.errorf("unexpected interface member %v", p.current)
		}
	}
	p.expect(itemBlockEnd)
	return i
}

func (p *parser) parseClassMemberSettings() (vis ast.Visibility, static, final, abstract bool) {
	var foundVis bool
	vis = ast.Public
	for {
		switch p.peek().typ {
		case itemAbstract:
			if abstract {
				p.errorf("found multiple abstract declarations")
			}
			abstract = true
			p.next()
		case itemPrivate, itemPublic, itemProtected:
			if foundVis {
				p.errorf("found multiple visibility declarations")
			}
			vis, foundVis = p.parseVisibility()
		case itemFinal:
			if final {
				p.errorf("found multiple final declarations")
			}
			final = true
			p.next()
		case itemStatic:
			if static {
				p.errorf("found multiple static declarations")
			}
			static = true
			p.next()
		default:
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/net/publicsuffix"
)

// handlePACFile serves an automatically-generated PAC (Proxy Auto-Config) file
// pointing to this proxy server.
func handlePACFile(w http.ResponseWriter, r *http.Request) {
	proxyAddr := r.Host

	if a := r.FormValue("a"); a != "" {
		if user, pass, ok := decodeBase64Credentials(a); ok {
			conf := getConfig()
			if conf.ValidCredentials(user, pass) {
				proxyForUserLock.RLock()
				p := proxyForUser[user]
				proxyForUserLock.RUnlock()
				if p != nil {
					client := r.RemoteAddr
					host, _, err := net.SplitHostPort(client)
					if err == nil {
						client = host
					}
					p.AllowIP(client)
					proxyHost, _, err := net.SplitHostPort(proxyAddr)
					if err == nil {
						proxyAddr = net.JoinHostPort(proxyHost, strconv.Itoa(p.Port))
					}
				}
			}
		}
	}

	w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
	fmt.Fprintf(w, pacTemplate, proxyAddr)
}

var pacTemplate = `function FindProxyForURL(url, host) {
	if (
		shExpMatch(url, "ftp:*") ||
		host == "localhost" ||
		isInNet(host, "127.0.0.0", "255.0.0.0") ||
		isInNet(host, "10.0.0.0", "255.0.0.0") ||
		isInNet(host, "172.16.0.0", "255.240.0.0") ||
		isInNet(host, "192.168.0.0", "255.255.0.0")
	) {
		return "DIRECT";
	}

	return "PROXY %s";
}`

type perUserProxy struct {
	User           string
	Port           int
	Handler        http.Handler
	ClientPlatform string
	allowedIPs     map[string]bool
	allowedIPLock  sync.RWMutex

	expectedDomains  map[string]bool
	expectedIPBlocks []*net.IPNet
	expectedNetLock  sync.RWMutex
}

func (c *config) newPerUserProxy(user string, portInfo customPortInfo) (*perUserProxy, error) {
	p := &perUserProxy{
		User:            user,
		Port:            portInfo.Port,
		ClientPlatform:  portInfo.ClientPlatform,
		Handler:         proxyHandler{user: user},
		allowedIPs:      map[string]bool{},
		expectedDomains: map[string]bool{},
	}

	for _, network := range portInfo.ExpectedNetworks {
		if _, nw, err := net.ParseCIDR(network); err == nil {
			p.expectedIPBlocks = append(p.expectedIPBlocks, nw)
		} else if ip := net.ParseIP(network); ip != nil {
			if ip4 := ip.To4(); ip4 != nil {
				p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip4, Mask: net.CIDRMask(32, 32)})
			} else {
				p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)})
			}
		} else {
			p.expectedDomains[network] = true
		}
	}

	proxyForUserLock.Lock()
	proxyForUser[user] = p
	proxyForUserLock.Unlock()
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", portInfo.Port))
	if err != nil {
		return nil, err
	}
	listener = tcpKeepAliveListener{listener.(*net.TCPListener)}

	go func() {
		<-shutdownChan
		listener.Close()
	}()

	server := http.Server{
		Handler:     p,
		IdleTimeout: c.CloseIdleConnections,
	}
	go server.Serve(listener)
	log.Printf("opened per-user listener for %s on port %d", user, portInfo.Port)

	return p, nil
}

func (p *perUserProxy) AllowIP(ip string) {
	p.allowedIPLock.Lock()
	p.allowedIPs[ip] = true
	p.allowedIPLock.Unlock()
	log.Printf("Added IP address %s, authenticated as %s, on port %d", ip, p.User, p.Port)

	domain := rdnsDomain(ip)
	if domain != "" {
		p.expectedNetLock.Lock()
		alreadyExpected := p.expectedDomains[domain]
		if !alreadyExpected {
			p.expectedDomains[domain] = true
		}
		p.expectedNetLock.Unlock()
		if !alreadyExpected {
			log.Printf("Added %s to the list of expected domains on port %d", domain, p.Port)
		}
	}
}

// rdnsDomain returns the base domain name of ip's reverse-DNS hostname (or the
// empty string if it is unavailable).
func rdnsDomain(ip string) string {
	names, err := net.LookupAddr(ip)
	if err != nil || len(names) == 0 {
		return ""
	}
	host := strings.TrimSuffix(names[0], ".")
	ps := publicsuffix.List.PublicSuffix(host)
	dot := strings.LastIndex(strings.TrimSuffix(strings.TrimSuffix(host, ps), "."), ".")
	if dot == -1 {
		return host
	}
	return host[dot+1:]
}

func (p *perUserProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	p.allowedIPLock.RLock()
	ok := p.allowedIPs[host]
	p.allowedIPLock.RUnlock()

	if ok {
		p.Handler.ServeHTTP(w, r)
		return
	}

	// This client's IP address is not pre-authorized for this port, but
	// maybe it sent credentials and we can authorize it now.
	// We accept credentials in either the Proxy-Authorization header or
	// a URL parameter named "a".
	conf := getConfig()

	user, pass, ok := ProxyCredentials(r)
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in Proxy-Authorization header from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	user, pass, ok = decodeBase64Credentials(r.FormValue("a"))
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in URL parameter from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	expectedNetwork := false
	ip := net.ParseIP(host)
	for _, nw := range p.expectedIPBlocks {
		if nw.Contains(ip) {
			expectedNetwork = true
			break
		}
	}

	if !expectedNetwork {
		names, err := net.LookupAddr(host)
		if err == nil {
			p.expectedNetLock.RLock()
		nameListLoop:
			for _, name := range names {
				name = strings.TrimSuffix(name, ".")
				for {
					if p.expectedDomains[name] {
						expectedNetwork = true
						break nameListLoop
					}
					dot := strings.Index(name, ".")
					if dot == -1 {
						continue nameListLoop
					}
					name = name[dot+1:]
				}
			}
			p.expectedNetLock.RUnlock()
		}
	}

	if expectedNetwork {
		pf := platform(r.Header.Get("User-Agent"))
		if p.ClientPlatform != "" && pf == p.ClientPlatform || darwinPlatforms[p.ClientPlatform] && pf == "Darwin" {
			log.Printf("Accepting %s as %s because of User-Agent string %q", host, p.ClientPlatform, r.Header.Get("User-Agent"))
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		}
	}

	log.Printf("Missing required proxy authentication from %v to %v, on port %d (User-Agent: %s, domain: %s)", r.RemoteAddr, r.URL, p.Port, r.Header.Get("User-Agent"), rdnsDomain(host))
	conf.send407(w)
}

var proxyForUser = make(map[string]*perUserProxy)
var proxyForUserLock sync.RWMutex

func (c *config) openPerUserPorts() {
	for user, portInfo := range c.CustomPorts {
		proxyForUserLock.RLock()
		p := proxyForUser[user]
		proxyForUserLock.RUnlock()
		if p == nil {
			_, err := c.newPerUserProxy(user, portInfo)
			if err != nil {
				log.Printf("error opening per-user listener for %s: %v", user, err)
			}
		}
	}
}

type portListEntry struct {
	User                 string
	Port                 int
	Platform             string
	AuthenticatedClients []string
	ExpectedNetworks     []string
}

func handlePerUserPortList(w http.ResponseWriter, r *http.Request) {
	var data []portListEntry

	proxyForUserLock.RLock()

	for _, p := range proxyForUser {
		var clients []string
		p.allowedIPLock.RLock()

		for c := range p.allowedIPs {
			clients = append(clients, c)
		}

		p.allowedIPLock.RUnlock()

		var networks []string
		p.expectedNetLock.RLock()
		for d := range p.expectedDomains {
			networks = append(networks, d)
		}
		for _, nw := range p.expectedIPBlocks {
			networks = append(networks, nw.String())
		}
		p.expectedNetLock.RUnlock()

		data = append(data, portListEntry{
			User:                 p.User,
			Port:                 p.Port,
			Platform:             p.ClientPlatform,
			AuthenticatedClients: clients,
			ExpectedNetworks:     networks,
		})
	}

	proxyForUserLock.RUnlock()

	ServeJSON(w, r, data)
}

func handlePerUserAuthenticate(w http.ResponseWriter, r *http.Request) {
	user := r.FormValue("user")
	if user == "" {
		http.Error(w, `You must specify which user to authenticate with the "user" form parameter.`, 400)
		return
	}
	proxyForUserLock.RLock()
	p := proxyForUser[user]
	proxyForUserLock.RUnlock()
	if p == nil {
		http.Error(w, user+" does not have a per-user proxy port set up.", 500)
		return
	}

	ip := r.FormValue("ip")
	if ip == "" {
		http.Error(w, `You must specify the client IP address with the "ip" form parameter.`, 400)
		return
	}

	p.AllowIP(ip)
	fmt.Fprintf(w, "Added %s as an authenticated IP address for %s.", ip, user)
}
<commit_msg>For rDNS, fall back to SOA record if PTR is not available.<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/miekg/dns"

	"golang.org/x/net/publicsuffix"
)

// handlePACFile serves an automatically-generated PAC (Proxy Auto-Config) file
// pointing to this proxy server.
func handlePACFile(w http.ResponseWriter, r *http.Request) {
	proxyAddr := r.Host

	if a := r.FormValue("a"); a != "" {
		if user, pass, ok := decodeBase64Credentials(a); ok {
			conf := getConfig()
			if conf.ValidCredentials(user, pass) {
				proxyForUserLock.RLock()
				p := proxyForUser[user]
				proxyForUserLock.RUnlock()
				if p != nil {
					client := r.RemoteAddr
					host, _, err := net.SplitHostPort(client)
					if err == nil {
						client = host
					}
					p.AllowIP(client)
					proxyHost, _, err := net.SplitHostPort(proxyAddr)
					if err == nil {
						proxyAddr = net.JoinHostPort(proxyHost, strconv.Itoa(p.Port))
					}
				}
			}
		}
	}

	w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
	fmt.Fprintf(w, pacTemplate, proxyAddr)
}

var pacTemplate = `function FindProxyForURL(url, host) {
	if (
		shExpMatch(url, "ftp:*") ||
		host == "localhost" ||
		isInNet(host, "127.0.0.0", "255.0.0.0") ||
		isInNet(host, "10.0.0.0", "255.0.0.0") ||
		isInNet(host, "172.16.0.0", "255.240.0.0") ||
		isInNet(host, "192.168.0.0", "255.255.0.0")
	) {
		return "DIRECT";
	}

	return "PROXY %s";
}`

type perUserProxy struct {
	User           string
	Port           int
	Handler        http.Handler
	ClientPlatform string
	allowedIPs     map[string]bool
	allowedIPLock  sync.RWMutex

	expectedDomains  map[string]bool
	expectedIPBlocks []*net.IPNet
	expectedNetLock  sync.RWMutex
}

func (c *config) newPerUserProxy(user string, portInfo customPortInfo) (*perUserProxy, error) {
	p := &perUserProxy{
		User:            user,
		Port:            portInfo.Port,
		ClientPlatform:  portInfo.ClientPlatform,
		Handler:         proxyHandler{user: user},
		allowedIPs:      map[string]bool{},
		expectedDomains: map[string]bool{},
	}

	for _, network := range portInfo.ExpectedNetworks {
		if _, nw, err := net.ParseCIDR(network); err == nil {
			p.expectedIPBlocks = append(p.expectedIPBlocks, nw)
		} else if ip := net.ParseIP(network); ip != nil {
			if ip4 := ip.To4(); ip4 != nil {
				p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip4, Mask: net.CIDRMask(32, 32)})
			} else {
				p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)})
			}
		} else {
			p.expectedDomains[network] = true
		}
	}

	proxyForUserLock.Lock()
	proxyForUser[user] = p
	proxyForUserLock.Unlock()
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", portInfo.Port))
	if err != nil {
		return nil, err
	}
	listener = tcpKeepAliveListener{listener.(*net.TCPListener)}

	go func() {
		<-shutdownChan
		listener.Close()
	}()

	server := http.Server{
		Handler:     p,
		IdleTimeout: c.CloseIdleConnections,
	}
	go server.Serve(listener)
	log.Printf("opened per-user listener for %s on port %d", user, portInfo.Port)

	return p, nil
}

func (p *perUserProxy) AllowIP(ip string) {
	p.allowedIPLock.Lock()
	p.allowedIPs[ip] = true
	p.allowedIPLock.Unlock()
	log.Printf("Added IP address %s, authenticated as %s, on port %d", ip, p.User, p.Port)

	domain := rdnsDomain(ip)
	if domain != "" {
		p.expectedNetLock.Lock()
		alreadyExpected := p.expectedDomains[domain]
		if !alreadyExpected {
			p.expectedDomains[domain] = true
		}
		p.expectedNetLock.Unlock()
		if !alreadyExpected {
			log.Printf("Added %s to the list of expected domains on port %d", domain, p.Port)
		}
	}
}

// rdnsDomain returns the base domain name of ip's reverse-DNS hostname (or the
// empty string if it is unavailable).
func rdnsDomain(ip string) string {
	var host string
	names, err := net.LookupAddr(ip)
	if err == nil && len(names) > 0 {
		host = names[0]
	}
	if host == "" {
		// If a PTR record isn't available, fall back to SOA.
		host, _ = rdnsSOA(ip)
	}
	if host == "" {
		return ""
	}
	host = strings.TrimSuffix(host, ".")
	ps := publicsuffix.List.PublicSuffix(host)
	dot := strings.LastIndex(strings.TrimSuffix(strings.TrimSuffix(host, ps), "."), ".")
	if dot == -1 {
		return host
	}
	return host[dot+1:]
}

var dnsServer string

func init() {
	conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
	if err != nil || len(conf.Servers) == 0 {
		return
	}
	dnsServer = conf.Servers[0] + ":" + conf.Port
}

// rdnsSOA returns the nameserver from the SOA (start of authority) reverse-DNS
// record for ip.
func rdnsSOA(ip string) (server string, err error) {
	octets := strings.Split(ip, ".")
	if len(octets) != 4 {
		return "", errors.New("invalid IPv4 address")
	}
	octets[0], octets[1], octets[2], octets[3] = octets[3], octets[2], octets[1], octets[0]

	m := new(dns.Msg)

	for i := 0; i < 4; i++ {
		m.SetQuestion(strings.Join(octets[i:], ".")+".in-addr.arpa.", dns.TypeSOA)
		soa, err := dns.Exchange(m, dnsServer)
		if err != nil {
			return "", err
		}
		if soa.Rcode != dns.RcodeSuccess || len(soa.Answer) == 0 {
			continue
		}
		trsoa, ok := soa.Answer[0].(*dns.SOA)
		if !ok {
			continue
		}
		return trsoa.Ns, nil
	}

	return "", errors.New("SOA not found")
}

func (p *perUserProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	p.allowedIPLock.RLock()
	ok := p.allowedIPs[host]
	p.allowedIPLock.RUnlock()

	if ok {
		p.Handler.ServeHTTP(w, r)
		return
	}

	// This client's IP address is not pre-authorized for this port, but
	// maybe it sent credentials and we can authorize it now.
	// We accept credentials in either the Proxy-Authorization header or
	// a URL parameter named "a".
	conf := getConfig()

	user, pass, ok := ProxyCredentials(r)
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in Proxy-Authorization header from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	user, pass, ok = decodeBase64Credentials(r.FormValue("a"))
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in URL parameter from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	expectedNetwork := false
	ip := net.ParseIP(host)
	for _, nw := range p.expectedIPBlocks {
		if nw.Contains(ip) {
			expectedNetwork = true
			break
		}
	}

	if !expectedNetwork {
		names, err := net.LookupAddr(host)
		if err == nil {
			p.expectedNetLock.RLock()
		nameListLoop:
			for _, name := range names {
				name = strings.TrimSuffix(name, ".")
				for {
					if p.expectedDomains[name] {
						expectedNetwork = true
						break nameListLoop
					}
					dot := strings.Index(name, ".")
					if dot == -1 {
						continue nameListLoop
					}
					name = name[dot+1:]
				}
			}
			p.expectedNetLock.RUnlock()
		}
	}

	if expectedNetwork {
		pf := platform(r.Header.Get("User-Agent"))
		if p.ClientPlatform != "" && pf == p.ClientPlatform || darwinPlatforms[p.ClientPlatform] && pf == "Darwin" {
			log.Printf("Accepting %s as %s because of User-Agent string %q", host, p.ClientPlatform, r.Header.Get("User-Agent"))
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		}
	}

	log.Printf("Missing required proxy authentication from %v to %v, on port %d (User-Agent: %s, domain: %s)", r.RemoteAddr, r.URL, p.Port, r.Header.Get("User-Agent"), rdnsDomain(host))
	conf.send407(w)
}

var proxyForUser = make(map[string]*perUserProxy)
var proxyForUserLock sync.RWMutex

func (c *config) openPerUserPorts() {
	for user, portInfo := range c.CustomPorts {
		proxyForUserLock.RLock()
		p := proxyForUser[user]
		proxyForUserLock.RUnlock()
		if p == nil {
			_, err := c.newPerUserProxy(user, portInfo)
			if err != nil {
				log.Printf("error opening per-user listener for %s: %v", user, err)
			}
		}
	}
}

type portListEntry struct {
	User                 string
	Port                 int
	Platform             string
	AuthenticatedClients []string
	ExpectedNetworks     []string
}

func handlePerUserPortList(w http.ResponseWriter, r *http.Request) {
	var data []portListEntry

	proxyForUserLock.RLock()

	for _, p := range proxyForUser {
		var clients []string
		p.allowedIPLock.RLock()

		for c := range p.allowedIPs {
			clients = append(clients, c)
		}

		p.allowedIPLock.RUnlock()

		var networks []string
		p.expectedNetLock.RLock()
		for d := range p.expectedDomains {
			networks = append(networks, d)
		}
		for _, nw := range p.expectedIPBlocks {
			networks = append(networks, nw.String())
		}
		p.expectedNetLock.RUnlock()

		data = append(data, portListEntry{
			User:                 p.User,
			Port:                 p.Port,
			Platform:             p.ClientPlatform,
			AuthenticatedClients: clients,
			ExpectedNetworks:     networks,
		})
	}

	proxyForUserLock.RUnlock()

	ServeJSON(w, r, data)
}

func handlePerUserAuthenticate(w http.ResponseWriter, r *http.Request) {
	user := r.FormValue("user")
	if user == "" {
		http.Error(w, `You must specify which user to authenticate with the "user" form parameter.`, 400)
		return
	}
	proxyForUserLock.RLock()
	p := proxyForUser[user]
	proxyForUserLock.RUnlock()
	if p == nil {
		http.Error(w, user+" does not have a per-user proxy port set up.", 500)
		return
	}

	ip := r.FormValue("ip")
	if ip == "" {
		http.Error(w, `You must specify the client IP address with the "ip" form parameter.`, 400)
		return
	}

	p.AllowIP(ip)
	fmt.Fprintf(w, "Added %s as an authenticated IP address for %s.", ip, user)
}
<|endoftext|>


<commit_before>package epub

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"
)

const (
	// TODO
	temp = `<?xml version="1.0" encoding="UTF-8"?>
<package version="3.0" unique-identifier="pub-id" xmlns="http://www.idpf.org/2007/opf">
  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:identifier id="pub-id">urn:uuid:fe93046f-af57-475a-a0cb-a0d4bc99ba6d</dc:identifier>
    <dc:title>Your title here</dc:title>
    <dc:language>en</dc:language>
    <meta refines="#creator" property="role" scheme="marc:relators" id="role">aut</meta>
    <meta property="dcterms:modified">2011-01-01T12:00:00Z</meta>
  </metadata>
  <manifest>
    <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav" />
    <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
    <item id="section0001.xhtml" href="xhtml/section0001.xhtml" media-type="application/xhtml+xml" />
  </manifest>
  <spine toc="ncx">
    <itemref idref="section0001.xhtml" />
  </spine>
</package>
`
	pkgAuthorID       = "role"
	pkgAuthorData     = "aut"
	pkgAuthorProperty = "role"
	pkgAuthorRefines  = "#creator"
	pkgAuthorScheme   = "marc:relators"
	pkgCreatorID      = "creator"
	pkgFileTemplate   = `<?xml version="1.0" encoding="UTF-8"?>
<package version="3.0" unique-identifier="pub-id" xmlns="http://www.idpf.org/2007/opf">
  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:identifier id="pub-id"></dc:identifier>
    <dc:title></dc:title>
    <dc:language></dc:language>
  </metadata>
  <manifest>
  </manifest>
  <spine toc="ncx">
  </spine>
</package>
`
	pkgModifiedProperty = "dcterms:modified"
	pkgUniqueIdentifier = "pub-id"

	xmlnsDc = "http://purl.org/dc/elements/1.1/"
)

// pkg implements the package file (package.opf), which contains metadata about
// the EPUB (title, author, etc) as well as a list of files the EPUB contains.
//
// Sample: https://github.com/bmaupin/epub-samples/blob/master/minimal-v32/EPUB/package.opf
// Spec: http://www.idpf.org/epub/301/spec/epub-publications.html
type pkg struct {
	xml          *pkgRoot
	authorMeta   *pkgMeta
	modifiedMeta *pkgMeta
}

// This holds the actual XML for the package file
type pkgRoot struct {
	XMLName          xml.Name    `xml:"http://www.idpf.org/2007/opf package"`
	UniqueIdentifier string      `xml:"unique-identifier,attr"`
	Version          string      `xml:"version,attr"`
	Metadata         pkgMetadata `xml:"metadata"`
	ManifestItems    []pkgItem   `xml:"manifest>item"`
	Spine            pkgSpine    `xml:"spine"`
}

// <dc:creator>, e.g. the author
type pkgCreator struct {
	XMLName xml.Name `xml:"dc:creator"`
	ID      string   `xml:"id,attr"`
	Data    string   `xml:",chardata"`
}

// <dc:identifier>, where the UUID is stored
type pkgIdentifier struct {
	ID   string `xml:"id,attr"`
	Data string `xml:",chardata"`
}

// <item> elements, one per each file stored in the EPUB
type pkgItem struct {
	ID         string `xml:"id,attr"`
	Href       string `xml:"href,attr"`
	MediaType  string `xml:"media-type,attr"`
	Properties string `xml:"properties,attr,omitempty"`
}

// <itemref> elements, which define the reading order
type pkgItemref struct {
	Idref string `xml:"idref,attr"`
}

// The <meta> element, which contains modified date, role of the creator (e.g.
// author), etc
type pkgMeta struct {
	Refines  string `xml:"refines,attr,omitempty"`
	Property string `xml:"property,attr"`
	Scheme   string `xml:"scheme,attr,omitempty"`
	ID       string `xml:"id,attr,omitempty"`
	Data     string `xml:",chardata"`
}

// The <metadata> element
type pkgMetadata struct {
	XmlnsDc    string        `xml:"xmlns:dc,attr"`
	Identifier pkgIdentifier `xml:"dc:identifier"`
	Title      string        `xml:"dc:title"`
	Language   string        `xml:"dc:language"`
	Creator    *pkgCreator
	Meta       []pkgMeta `xml:"meta"`
}

// The <spine> element
type pkgSpine struct {
	Items []pkgItemref `xml:"itemref"`
	Toc   string       `xml:"toc,attr"`
}

// Constructor for pkg
func newPackage() *pkg {
	p := &pkg{
		xml: &pkgRoot{
			Metadata: pkgMetadata{
				XmlnsDc: xmlnsDc,
				Identifier: pkgIdentifier{
					ID: pkgUniqueIdentifier,
				},
			},
		},
	}

	err := xml.Unmarshal([]byte(pkgFileTemplate), &p.xml)
	if err != nil {
		panic(fmt.Sprintf(
			"Error unmarshalling package file XML: %s\n"+
				"\tp.xml=%#v\n"+
				"\tpkgFileTemplate=%s",
			err,
			*p.xml,
			pkgFileTemplate))
	}

	return p
}

func (p *pkg) addToManifest(id string, href string, mediaType string, properties string) {
	i := &pkgItem{
		ID:         id,
		Href:       href,
		MediaType:  mediaType,
		Properties: properties,
	}
	p.xml.ManifestItems = append(p.xml.ManifestItems, *i)
}

func (p *pkg) addToSpine(id string) {
	i := &pkgItemref{
		Idref: id,
	}

	p.xml.Spine.Items = append(p.xml.Spine.Items, *i)
}

func (p *pkg) setAuthor(author string) {
	p.xml.Metadata.Creator = &pkgCreator{
		Data: author,
		ID:   pkgCreatorID,
	}
	p.authorMeta = &pkgMeta{
		Data:     pkgAuthorData,
		ID:       pkgAuthorID,
		Property: pkgAuthorProperty,
		Refines:  pkgAuthorRefines,
		Scheme:   pkgAuthorScheme,
	}

	p.xml.Metadata.Meta = updateMeta(p.xml.Metadata.Meta, p.authorMeta)
}

func (p *pkg) setLang(lang string) {
	p.xml.Metadata.Language = lang
}

func (p *pkg) setModified(timestamp string) {
	p.modifiedMeta = &pkgMeta{
		Data:     timestamp,
		Property: pkgModifiedProperty,
	}

	p.xml.Metadata.Meta = updateMeta(p.xml.Metadata.Meta, p.modifiedMeta)
}

func (p *pkg) setTitle(title string) {
	p.xml.Metadata.Title = title
}

func (p *pkg) setUUID(uuid string) {
	p.xml.Metadata.Identifier.Data = uuid
}

// Update the <meta> element
func updateMeta(a []pkgMeta, m *pkgMeta) []pkgMeta {
	indexToReplace := -1

	if len(a) > 0 {
		// If we've already added the modified meta element to the meta array
		for i, meta := range a {
			if meta == *m {
				indexToReplace = i
				break
			}
		}
	}

	// If the array is empty or the meta element isn't in it
	if indexToReplace == -1 {
		// Add the meta element to the array of meta elements
		a = append(a, *m)

		// If the meta element is found
	} else {
		// Replace it
		a[indexToReplace] = *m
	}

	return a
}

// Write the package file to the temporary directory
func (p *pkg) write(tempDir string) {
	now := time.Now().UTC().Format("2006-01-02T15:04:05Z")
	p.setModified(now)

	pkgFilePath := filepath.Join(tempDir, contentFolderName, pkgFilename)

	output, err := xml.MarshalIndent(p.xml, "", "  ")
	if err != nil {
		panic(fmt.Sprintf(
			"Error marshalling XML for package file: %s\n"+
				"\tXML=%#v",
			err,
			p.xml))
	}
	// Add the xml header to the output
	pkgFileContent := append([]byte(xml.Header), output...)
	// It's generally nice to have files end with a newline
	pkgFileContent = append(pkgFileContent, "\n"...)

	if err := ioutil.WriteFile(pkgFilePath, []byte(pkgFileContent), filePermissions); err != nil {
		panic(fmt.Sprintf("Error writing package file: %s", err))
	}
}
<commit_msg>Clean up XML element examples<commit_after>package epub

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"
)

const (
	pkgAuthorID       = "role"
	pkgAuthorData     = "aut"
	pkgAuthorProperty = "role"
	pkgAuthorRefines  = "#creator"
	pkgAuthorScheme   = "marc:relators"
	pkgCreatorID      = "creator"
	pkgFileTemplate   = `<?xml version="1.0" encoding="UTF-8"?>
<package version="3.0" unique-identifier="pub-id" xmlns="http://www.idpf.org/2007/opf">
  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:identifier id="pub-id"></dc:identifier>
    <dc:title></dc:title>
    <dc:language></dc:language>
  </metadata>
  <manifest>
  </manifest>
  <spine toc="ncx">
  </spine>
</package>
`
	pkgModifiedProperty = "dcterms:modified"
	pkgUniqueIdentifier = "pub-id"

	xmlnsDc = "http://purl.org/dc/elements/1.1/"
)

// pkg implements the package file (package.opf), which contains metadata about
// the EPUB (title, author, etc) as well as a list of files the EPUB contains.
//
// Sample: https://github.com/bmaupin/epub-samples/blob/master/minimal-v32/EPUB/package.opf
// Spec: http://www.idpf.org/epub/301/spec/epub-publications.html
type pkg struct {
	xml          *pkgRoot
	authorMeta   *pkgMeta
	modifiedMeta *pkgMeta
}

// This holds the actual XML for the package file
type pkgRoot struct {
	XMLName          xml.Name    `xml:"http://www.idpf.org/2007/opf package"`
	UniqueIdentifier string      `xml:"unique-identifier,attr"`
	Version          string      `xml:"version,attr"`
	Metadata         pkgMetadata `xml:"metadata"`
	ManifestItems    []pkgItem   `xml:"manifest>item"`
	Spine            pkgSpine    `xml:"spine"`
}

// <dc:creator>, e.g. the author
type pkgCreator struct {
	XMLName xml.Name `xml:"dc:creator"`
	ID      string   `xml:"id,attr"`
	Data    string   `xml:",chardata"`
}

// <dc:identifier>, where the UUID is stored
// Ex: <dc:identifier id="pub-id">urn:uuid:fe93046f-af57-475a-a0cb-a0d4bc99ba6d</dc:identifier>
type pkgIdentifier struct {
	ID   string `xml:"id,attr"`
	Data string `xml:",chardata"`
}

// <item> elements, one per each file stored in the EPUB
// Ex: <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav" />
//     <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
//     <item id="section0001.xhtml" href="xhtml/section0001.xhtml" media-type="application/xhtml+xml" />
type pkgItem struct {
	ID         string `xml:"id,attr"`
	Href       string `xml:"href,attr"`
	MediaType  string `xml:"media-type,attr"`
	Properties string `xml:"properties,attr,omitempty"`
}

// <itemref> elements, which define the reading order
// Ex: <itemref idref="section0001.xhtml" />
type pkgItemref struct {
	Idref string `xml:"idref,attr"`
}

// The <meta> element, which contains modified date, role of the creator (e.g.
// author), etc
// Ex: <meta refines="#creator" property="role" scheme="marc:relators" id="role">aut</meta>
//     <meta property="dcterms:modified">2011-01-01T12:00:00Z</meta>
type pkgMeta struct {
	Refines  string `xml:"refines,attr,omitempty"`
	Property string `xml:"property,attr"`
	Scheme   string `xml:"scheme,attr,omitempty"`
	ID       string `xml:"id,attr,omitempty"`
	Data     string `xml:",chardata"`
}

// The <metadata> element
type pkgMetadata struct {
	XmlnsDc    string        `xml:"xmlns:dc,attr"`
	Identifier pkgIdentifier `xml:"dc:identifier"`
	// Ex: <dc:title>Your title here</dc:title>
	Title string `xml:"dc:title"`
	// Ex: <dc:language>en</dc:language>
	Language string `xml:"dc:language"`
	Creator  *pkgCreator
	Meta     []pkgMeta `xml:"meta"`
}

// The <spine> element
type pkgSpine struct {
	Items []pkgItemref `xml:"itemref"`
	Toc   string       `xml:"toc,attr"`
}

// Constructor for pkg
func newPackage() *pkg {
	p := &pkg{
		xml: &pkgRoot{
			Metadata: pkgMetadata{
				XmlnsDc: xmlnsDc,
				Identifier: pkgIdentifier{
					ID: pkgUniqueIdentifier,
				},
			},
		},
	}

	err := xml.Unmarshal([]byte(pkgFileTemplate), &p.xml)
	if err != nil {
		panic(fmt.Sprintf(
			"Error unmarshalling package file XML: %s\n"+
				"\tp.xml=%#v\n"+
				"\tpkgFileTemplate=%s",
			err,
			*p.xml,
			pkgFileTemplate))
	}

	return p
}

func (p *pkg) addToManifest(id string, href string, mediaType string, properties string) {
	i := &pkgItem{
		ID:         id,
		Href:       href,
		MediaType:  mediaType,
		Properties: properties,
	}
	p.xml.ManifestItems = append(p.xml.ManifestItems, *i)
}

func (p *pkg) addToSpine(id string) {
	i := &pkgItemref{
		Idref: id,
	}

	p.xml.Spine.Items = append(p.xml.Spine.Items, *i)
}

func (p *pkg) setAuthor(author string) {
	p.xml.Metadata.Creator = &pkgCreator{
		Data: author,
		ID:   pkgCreatorID,
	}
	p.authorMeta = &pkgMeta{
		Data:     pkgAuthorData,
		ID:       pkgAuthorID,
		Property: pkgAuthorProperty,
		Refines:  pkgAuthorRefines,
		Scheme:   pkgAuthorScheme,
	}

	p.xml.Metadata.Meta = updateMeta(p.xml.Metadata.Meta, p.authorMeta)
}

func (p *pkg) setLang(lang string) {
	p.xml.Metadata.Language = lang
}

func (p *pkg) setModified(timestamp string) {
	p.modifiedMeta = &pkgMeta{
		Data:     timestamp,
		Property: pkgModifiedProperty,
	}

	p.xml.Metadata.Meta = updateMeta(p.xml.Metadata.Meta, p.modifiedMeta)
}

func (p *pkg) setTitle(title string) {
	p.xml.Metadata.Title = title
}

func (p *pkg) setUUID(uuid string) {
	p.xml.Metadata.Identifier.Data = uuid
}

// Update the <meta> element
func updateMeta(a []pkgMeta, m *pkgMeta) []pkgMeta {
	indexToReplace := -1

	if len(a) > 0 {
		// If we've already added the modified meta element to the meta array
		for i, meta := range a {
			if meta == *m {
				indexToReplace = i
				break
			}
		}
	}

	// If the array is empty or the meta element isn't in it
	if indexToReplace == -1 {
		// Add the meta element to the array of meta elements
		a = append(a, *m)

		// If the meta element is found
	} else {
		// Replace it
		a[indexToReplace] = *m
	}

	return a
}

// Write the package file to the temporary directory
func (p *pkg) write(tempDir string) {
	now := time.Now().UTC().Format("2006-01-02T15:04:05Z")
	p.setModified(now)

	pkgFilePath := filepath.Join(tempDir, contentFolderName, pkgFilename)

	output, err := xml.MarshalIndent(p.xml, "", "  ")
	if err != nil {
		panic(fmt.Sprintf(
			"Error marshalling XML for package file: %s\n"+
				"\tXML=%#v",
			err,
			p.xml))
	}
	// Add the xml header to the output
	pkgFileContent := append([]byte(xml.Header), output...)
	// It's generally nice to have files end with a newline
	pkgFileContent = append(pkgFileContent, "\n"...)

	if err := ioutil.WriteFile(pkgFilePath, []byte(pkgFileContent), filePermissions); err != nil {
		panic(fmt.Sprintf("Error writing package file: %s", err))
	}
}
<|endoftext|>


<commit_before>package luar

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

type luaPointerWrapper struct {
	L   *lua.LState
	Ptr interface{}
}

func (w *luaPointerWrapper) Index(key lua.LValue) (lua.LValue, error) {
	ref := reflect.ValueOf(w.Ptr)
	refType := ref.Type()

	// Check for method
	keyLString, ok := key.(lua.LString)
	keyString := getExportedName(string(keyLString))
	if ok {
		if method, ok := refType.MethodByName(keyString); ok {
			return New(w.L, method.Func.Interface()), nil
		}
	}

	// Check for field
	for ref.Kind() == reflect.Ptr {
		ref = ref.Elem()
	}
	if ref.Kind() != reflect.Struct {
		return nil, errors.New("cannot index non-struct pointer type")
	}

	if field := ref.FieldByName(keyString); field.IsValid() {
		if !field.CanInterface() {
			return nil, errors.New("cannot interface field " + keyString)
		}
		if val := New(w.L, field.Interface()); val != nil {
			return val, nil
		}
	}

	return lua.LNil, nil
}

func (w *luaPointerWrapper) NewIndex(key lua.LValue, value lua.LValue) error {
	ref := reflect.ValueOf(w.Ptr).Elem()

	if ref.Kind() != reflect.Struct {
		return errors.New("cannot new index non-struct pointer type")
	}

	keyLString, ok := key.(lua.LString)
	if !ok {
		return errors.New("invalid non-string key")
	}

	keyString := string(keyLString)
	field := ref.FieldByName(keyString)
	if !field.IsValid() {
		return errors.New("unknown field " + keyString)
	}
	if !field.CanSet() {
		return errors.New("cannot set field " + keyString)
	}
	field.Set(lValueToReflect(value, field.Type()))
	return nil
}

func (w *luaPointerWrapper) Len() (lua.LValue, error) {
	return nil, errors.New("cannot # ptr")
}

func (w *luaPointerWrapper) Call(...lua.LValue) ([]lua.LValue, error) {
	return nil, errors.New("cannot call ptr")
}

func (w *luaPointerWrapper) String() (string, error) {
	if stringer, ok := w.Ptr.(fmt.Stringer); ok {
		return stringer.String(), nil
	}
	return reflect.ValueOf(w.Ptr).String(), nil
}

func (w *luaPointerWrapper) Equals(other luaWrapper) (lua.LValue, error) {
	v, ok := other.(*luaPointerWrapper)
	if !ok {
		return lua.LFalse, nil
	}
	return lua.LBool(w.Ptr == v.Ptr), nil
}

func (w *luaPointerWrapper) Unwrap() interface{} {
	return w.Ptr
}
<commit_msg>remove useless condition<commit_after>package luar

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

type luaPointerWrapper struct {
	L   *lua.LState
	Ptr interface{}
}

func (w *luaPointerWrapper) Index(key lua.LValue) (lua.LValue, error) {
	ref := reflect.ValueOf(w.Ptr)
	refType := ref.Type()

	// Check for method
	keyLString, ok := key.(lua.LString)
	keyString := getExportedName(string(keyLString))
	if ok {
		if method, ok := refType.MethodByName(keyString); ok {
			return New(w.L, method.Func.Interface()), nil
		}
	}

	// Check for field
	ref = ref.Elem()
	if ref.Kind() != reflect.Struct {
		return nil, errors.New("cannot index non-struct pointer type")
	}

	if field := ref.FieldByName(keyString); field.IsValid() {
		if !field.CanInterface() {
			return nil, errors.New("cannot interface field " + keyString)
		}
		if val := New(w.L, field.Interface()); val != nil {
			return val, nil
		}
	}

	return lua.LNil, nil
}

func (w *luaPointerWrapper) NewIndex(key lua.LValue, value lua.LValue) error {
	ref := reflect.ValueOf(w.Ptr).Elem()

	if ref.Kind() != reflect.Struct {
		return errors.New("cannot new index non-struct pointer type")
	}

	keyLString, ok := key.(lua.LString)
	if !ok {
		return errors.New("invalid non-string key")
	}

	keyString := string(keyLString)
	field := ref.FieldByName(keyString)
	if !field.IsValid() {
		return errors.New("unknown field " + keyString)
	}
	if !field.CanSet() {
		return errors.New("cannot set field " + keyString)
	}
	field.Set(lValueToReflect(value, field.Type()))
	return nil
}

func (w *luaPointerWrapper) Len() (lua.LValue, error) {
	return nil, errors.New("cannot # ptr")
}

func (w *luaPointerWrapper) Call(...lua.LValue) ([]lua.LValue, error) {
	return nil, errors.New("cannot call ptr")
}

func (w *luaPointerWrapper) String() (string, error) {
	if stringer, ok := w.Ptr.(fmt.Stringer); ok {
		return stringer.String(), nil
	}
	return reflect.ValueOf(w.Ptr).String(), nil
}

func (w *luaPointerWrapper) Equals(other luaWrapper) (lua.LValue, error) {
	v, ok := other.(*luaPointerWrapper)
	if !ok {
		return lua.LFalse, nil
	}
	return lua.LBool(w.Ptr == v.Ptr), nil
}

func (w *luaPointerWrapper) Unwrap() interface{} {
	return w.Ptr
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/FactomProject/factom"
)

type extids []string

func (e *extids) String() string {
	return fmt.Sprint(*e)
}

func (e *extids) Set(s string) error {
	*e = append(*e, s)
	return nil
}

// put commits then reveals an entry to factomd
func put(args []string) {
	os.Args = args
	var (
		cid  = flag.String("c", "", "hex encoded chainid for the entry")
		eids extids
	)
	flag.Var(&eids, "e", "external id for the entry")
	flag.Parse()
	args = flag.Args()

	if len(args) < 1 {
		man("put")
		return
	}
	name := args[0]

	e := factom.NewEntry()

	// use the default chainid and extids from the config file
	econf := ReadConfig().Entry
	if econf.Chainid != "" {
		e.ChainID = econf.Chainid
	}
	if *cid != "" {
		e.ChainID = *cid
	}
	if econf.Extid != "" {
		e.ExtIDs = append(e.ExtIDs, econf.Extid)
	}

	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, hex.EncodeToString([]byte(v)))
	}

	// Entry.Content is read from stdin
	if p, err := ioutil.ReadAll(os.Stdin); err != nil {
		errorln(err)
		return
	} else if size := len(p); size > 10240 {
		errorln(fmt.Errorf("Entry of %d bytes is too large", size))
		return
	} else {
		e.Content = hex.EncodeToString(p)
	}

	if err := factom.CommitEntry(e, name); err != nil {
		errorln(err)
		return
	}
	time.Sleep(10 * time.Second)
	if err := factom.RevealEntry(e); err != nil {
		errorln(err)
		return
	}
}
<commit_msg>added entry hash return to put<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/FactomProject/factom"
)

type extids []string

func (e *extids) String() string {
	return fmt.Sprint(*e)
}

func (e *extids) Set(s string) error {
	*e = append(*e, s)
	return nil
}

// put commits then reveals an entry to factomd
func put(args []string) {
	os.Args = args
	var (
		cid  = flag.String("c", "", "hex encoded chainid for the entry")
		eids extids
	)
	flag.Var(&eids, "e", "external id for the entry")
	flag.Parse()
	args = flag.Args()

	if len(args) < 1 {
		man("put")
		return
	}
	name := args[0]

	e := factom.NewEntry()

	// use the default chainid and extids from the config file
	econf := ReadConfig().Entry
	if econf.Chainid != "" {
		e.ChainID = econf.Chainid
	}
	if *cid != "" {
		e.ChainID = *cid
	}
	if econf.Extid != "" {
		e.ExtIDs = append(e.ExtIDs, econf.Extid)
	}

	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, hex.EncodeToString([]byte(v)))
	}

	// Entry.Content is read from stdin
	if p, err := ioutil.ReadAll(os.Stdin); err != nil {
		errorln(err)
		return
	} else if size := len(p); size > 10240 {
		errorln(fmt.Errorf("Entry of %d bytes is too large", size))
		return
	} else {
		e.Content = hex.EncodeToString(p)
	}

	fmt.Printf("Creating Entry: %x\n", e.Hash())
	if err := factom.CommitEntry(e, name); err != nil {
		errorln(err)
		return
	}
	time.Sleep(10 * time.Second)
	if err := factom.RevealEntry(e); err != nil {
		errorln(err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"./detect"
	"./fileutil"
)

/*

# the plan

qst: run things quickly

qst - detects the current project type and runs it
qst hello.rb - runs `ruby hello.rb`
qst hello.go - compiles & runs hello.go

*/

var delay = flag.Duration("delay", 1*time.Second, "time to wait until restart")
var autoRestart = flag.Bool("autorestart", true, "automatically restart after command exists")
var command = flag.String("command", "", "command to run ({file} will be substituted)")

func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <file>\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		flag.Usage()
		os.Exit(1)
	}

	file := args[0]
	// if !isFile(file) {
	// 	fmt.Fprintf(os.Stderr, "Error: %s is not a file.\n", file)
	// 	os.Exit(1)
	// }

	var cmd string
	if command != nil && strings.TrimSpace(*command) != "" {
		cmd = *command
	} else {
		project, err := detect.Detect(file)
		if err != nil {
			log.Fatal("error: ", err)
		}
		log.Printf("detected a %s project", project.Id)
		projectCmd, found := project.Commands["run"]
		if !found {
			log.Fatalf("%s doesn't support `run'", project.Id)
		}
		cmd = projectCmd
	}
	cmd = strings.Replace(cmd, "{file}", file, -1)
	if err := os.Chdir(fileutil.Dir(file)); err != nil {
		log.Fatal(err)
	}
	log.Printf("command to run: `%s'", cmd)

	runner := MakeRunner(cmd, *autoRestart)
	go runCmd(file, runner)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
	s := <-c
	log.Printf("got signal: %s, exiting...", s)
	runner.Stop()
}

func runCmd(file string, runner *Runner) {
	runner.Start()
	lastMtime := time.Now()
	for {
		info, err := os.Stat(file)
		if os.IsNotExist(err) {
			log.Fatalf("`%s' disappeared, exiting", file)
		}

		mtime := info.ModTime()
		if mtime.After(lastMtime) {
			log.Printf("`%s' changed, trying to restart", file)
			runner.Restart()
		}

		lastMtime = mtime
		time.Sleep(1 * time.Second)
	}
}

type Runner struct {
	cmd         *exec.Cmd
	shellCmd    string
	started     bool
	autoRestart bool
	restarting  bool
}

func MakeRunner(shellCmd string, autoRestart bool) *Runner {
	return &Runner{nil, shellCmd, false, autoRestart, false}
}

func (r *Runner) Start() error {
	if r.started {
		return errors.New("already started, use Restart()")
	}

	r.started = true
	go func() {
		for {
			log.Printf("running %s", r.shellCmd)
			r.cmd = exec.Command("sh", "-c", r.shellCmd)
			r.cmd.Stderr = os.Stderr
			r.cmd.Stdout = os.Stdout
			r.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
			err := r.cmd.Run()
			var result interface{}
			if err != nil {
				result = err
			} else {
				result = r.cmd.ProcessState
			}
			log.Printf("%s finished: %s", r.shellCmd, result)

			time.Sleep(*delay)
			if !r.restarting && !r.autoRestart {
				r.started = false
				break
			}

			r.restarting = false
		}
	}()

	return nil
}

func (r *Runner) Kill() error {
	pgid, err := syscall.Getpgid(r.cmd.Process.Pid)
	if err == nil {
		syscall.Kill(-pgid, syscall.SIGTERM)
	}
	return err
}

func (r *Runner) Restart() error {
	r.restarting = true
	if r.started {
		return r.Kill()
	} else {
		return r.Start()
	}
}

func (r *Runner) Stop() {
	r.autoRestart = false
	r.Kill()
}

func isFile(file string) bool {
	info, err := os.Stat(file)
	return err == nil && !info.IsDir()
}
<commit_msg>use absolute file path to prevent errors after chdir.<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"./detect"
	"./fileutil"
)

/*

# the plan

qst: run things quickly

qst - detects the current project type and runs it
qst hello.rb - runs `ruby hello.rb`
qst hello.go - compiles & runs hello.go

*/

var delay = flag.Duration("delay", 1*time.Second, "time to wait until restart")
var autoRestart = flag.Bool("autorestart", true, "automatically restart after command exists")
var command = flag.String("command", "", "command to run ({file} will be substituted)")

func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <file>\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		flag.Usage()
		os.Exit(1)
	}

	file := args[0]
	// if !isFile(file) {
	// 	fmt.Fprintf(os.Stderr, "Error: %s is not a file.\n", file)
	// 	os.Exit(1)
	// }

	var cmd string
	if command != nil && strings.TrimSpace(*command) != "" {
		cmd = *command
	} else {
		project, err := detect.Detect(file)
		if err != nil {
			log.Fatal("error: ", err)
		}
		log.Printf("detected a %s project", project.Id)
		projectCmd, found := project.Commands["run"]
		if !found {
			log.Fatalf("%s doesn't support `run'", project.Id)
		}
		cmd = projectCmd
	}
	file, _ = filepath.Abs(file)
	cmd = strings.Replace(cmd, "{file}", file, -1)
	if err := os.Chdir(fileutil.Dir(file)); err != nil {
		log.Fatal(err)
	}
	log.Printf("command to run: `%s'", cmd)

	runner := MakeRunner(cmd, *autoRestart)
	go runCmd(file, runner)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
	s := <-c
	log.Printf("got signal: %s, exiting...", s)
	runner.Stop()
}

func runCmd(file string, runner *Runner) {
	runner.Start()
	lastMtime := time.Now()
	for {
		info, err := os.Stat(file)
		if os.IsNotExist(err) {
			log.Fatalf("`%s' disappeared, exiting", file)
		}

		mtime := info.ModTime()
		if mtime.After(lastMtime) {
			log.Printf("`%s' changed, trying to restart", file)
			runner.Restart()
		}

		lastMtime = mtime
		time.Sleep(1 * time.Second)
	}
}

type Runner struct {
	cmd         *exec.Cmd
	shellCmd    string
	started     bool
	autoRestart bool
	restarting  bool
}

func MakeRunner(shellCmd string, autoRestart bool) *Runner {
	return &Runner{nil, shellCmd, false, autoRestart, false}
}

func (r *Runner) Start() error {
	if r.started {
		return errors.New("already started, use Restart()")
	}

	r.started = true
	go func() {
		for {
			log.Printf("running %s", r.shellCmd)
			r.cmd = exec.Command("sh", "-c", r.shellCmd)
			r.cmd.Stderr = os.Stderr
			r.cmd.Stdout = os.Stdout
			r.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
			err := r.cmd.Run()
			var result interface{}
			if err != nil {
				result = err
			} else {
				result = r.cmd.ProcessState
			}
			log.Printf("%s finished: %s", r.shellCmd, result)

			time.Sleep(*delay)
			if !r.restarting && !r.autoRestart {
				r.started = false
				break
			}

			r.restarting = false
		}
	}()

	return nil
}

func (r *Runner) Kill() error {
	pgid, err := syscall.Getpgid(r.cmd.Process.Pid)
	if err == nil {
		syscall.Kill(-pgid, syscall.SIGTERM)
	}
	return err
}

func (r *Runner) Restart() error {
	r.restarting = true
	if r.started {
		return r.Kill()
	} else {
		return r.Start()
	}
}

func (r *Runner) Stop() {
	r.autoRestart = false
	r.Kill()
}

func isFile(file string) bool {
	info, err := os.Stat(file)
	return err == nil && !info.IsDir()
}
<|endoftext|>


<commit_before>package pt

import (
	"math"
)

type Ray struct {
	Origin, Direction Vector
}

func (r Ray) Position(t float64) Vector {
	return r.Origin.Add(r.Direction.Mul(t))
}

func (n Ray) Reflect(i Ray) Ray {
	return Ray{n.Origin, n.Direction.Reflect(i.Direction)}
}

func (n Ray) Reflectance(i Ray, n1, n2 float64) float64 {
	nr := n1 / n2
	cosI := -n.Direction.Dot(i.Direction)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return 1
	}
	cosT := math.Sqrt(1 - sinT2)
	rOrth := (n1*cosI - n2*cosT) / (n1*cosI + n2*cosT)
	rPar := (n2*cosI - n1*cosT) / (n2*cosI + n1*cosT)
	return (rOrth*rOrth + rPar*rPar) / 2
}

func (r Ray) UniformBounce(u, v float64) Ray {
	rx := u * 2 * math.Pi
	ry := v * 2 * math.Pi
	x := math.Sin(rx) * math.Sin(ry)
	y := math.Sin(rx) * math.Cos(ry)
	z := math.Cos(rx)
	d := Vector{x, y, z}
	if d.Dot(r.Direction) < 0 {
		d = d.Mul(-1)
	}
	return Ray{r.Origin, d}
}

func (r Ray) WeightedBounce(u, v float64) Ray {
	m1 := math.Sqrt(u)
	m2 := math.Sqrt(1 - u)
	a := v * 2 * math.Pi
	s := r.Direction.Cross(r.Direction.MinAxis())
	t := r.Direction.Cross(s)
	d := Vector{}
	d = d.Add(s.Mul(m1 * math.Cos(a)))
	d = d.Add(t.Mul(m1 * math.Sin(a)))
	d = d.Add(r.Direction.Mul(m2))
	return Ray{r.Origin, d}
}

func (r Ray) ConeBounce(theta, u, v float64) Ray {
	// TODO: make weighted
	theta = math.Acos(math.Cos(theta) + (1-math.Cos(theta))*u)
	m1 := math.Sin(theta)
	m2 := math.Cos(theta)
	a := v * 2 * math.Pi
	s := r.Direction.Cross(r.Direction.MinAxis())
	t := r.Direction.Cross(s)
	d := Vector{}
	d = d.Add(s.Mul(m1 * math.Cos(a)))
	d = d.Add(t.Mul(m1 * math.Sin(a)))
	d = d.Add(r.Direction.Mul(m2))
	return Ray{r.Origin, d}
}

func (r Ray) Bounce(i Ray, material Material, p, u, v float64) (Ray, bool) {
	if p < r.Reflectance(i, 1, material.Index) {
		reflected := r.Reflect(i)
		return reflected.ConeBounce(material.Gloss, u, v), true
	} else {
		return r.WeightedBounce(u, v), false
	}
}
<commit_msg>ray bounce optimization<commit_after>package pt

import (
	"math"
)

type Ray struct {
	Origin, Direction Vector
}

func (r Ray) Position(t float64) Vector {
	return r.Origin.Add(r.Direction.Mul(t))
}

func (n Ray) Reflect(i Ray) Ray {
	return Ray{n.Origin, n.Direction.Reflect(i.Direction)}
}

func (n Ray) Reflectance(i Ray, n1, n2 float64) float64 {
	nr := n1 / n2
	cosI := -n.Direction.Dot(i.Direction)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return 1
	}
	cosT := math.Sqrt(1 - sinT2)
	rOrth := (n1*cosI - n2*cosT) / (n1*cosI + n2*cosT)
	rPar := (n2*cosI - n1*cosT) / (n2*cosI + n1*cosT)
	return (rOrth*rOrth + rPar*rPar) / 2
}

func (r Ray) UniformBounce(u, v float64) Ray {
	rx := u * 2 * math.Pi
	ry := v * 2 * math.Pi
	x := math.Sin(rx) * math.Sin(ry)
	y := math.Sin(rx) * math.Cos(ry)
	z := math.Cos(rx)
	d := Vector{x, y, z}
	if d.Dot(r.Direction) < 0 {
		d = d.Mul(-1)
	}
	return Ray{r.Origin, d}
}

func (r Ray) WeightedBounce(u, v float64) Ray {
	m1 := math.Sqrt(u)
	m2 := math.Sqrt(1 - u)
	a := v * 2 * math.Pi
	s := r.Direction.Cross(r.Direction.MinAxis())
	t := r.Direction.Cross(s)
	d := Vector{}
	d = d.Add(s.Mul(m1 * math.Cos(a)))
	d = d.Add(t.Mul(m1 * math.Sin(a)))
	d = d.Add(r.Direction.Mul(m2))
	return Ray{r.Origin, d}
}

func (r Ray) ConeBounce(theta, u, v float64) Ray {
	// TODO: make weighted
	if theta < EPS {
		return r
	}
	theta = math.Acos(math.Cos(theta) + (1-math.Cos(theta))*u)
	m1 := math.Sin(theta)
	m2 := math.Cos(theta)
	a := v * 2 * math.Pi
	s := r.Direction.Cross(r.Direction.MinAxis())
	t := r.Direction.Cross(s)
	d := Vector{}
	d = d.Add(s.Mul(m1 * math.Cos(a)))
	d = d.Add(t.Mul(m1 * math.Sin(a)))
	d = d.Add(r.Direction.Mul(m2))
	return Ray{r.Origin, d}
}

func (r Ray) Bounce(i Ray, material Material, p, u, v float64) (Ray, bool) {
	if p < r.Reflectance(i, 1, material.Index) {
		reflected := r.Reflect(i)
		return reflected.ConeBounce(material.Gloss, u, v), true
	} else {
		return r.WeightedBounce(u, v), false
	}
}
<|endoftext|>


<commit_before>package node

import (
	"erlang/term"
)

type rexRPC struct {
	gsi *GenServerImpl
}

func (nk *rexRPC) Behaviour() (Behaviour, map[string]interface{}) {
	nk.gsi = &GenServerImpl{}
	return nk.gsi, nk.gsi.Options()
}

func (nk *rexRPC) Init(args ...interface{}) {
	nLog("REX: Init: %#v", args)
}

func (nk *rexRPC) HandleCast(message *term.Term) {
	nLog("REX: HandleCast: %#v", *message)
}

func (nk *rexRPC) HandleCall(message *term.Term, from *term.Tuple) (reply *term.Term) {
	nLog("REX: HandleCall: %#v, From: %#v", *message, *from)
	replyTerm := term.Term(term.Atom("rpc reply"))
	reply = &replyTerm
	return
}

func (nk *rexRPC) HandleInfo(message *term.Term) {
	nLog("REX: HandleInfo: %#v", *message)
}

func (nk *rexRPC) Terminate(reason interface{}) {
	nLog("REX: Terminate: %#v", reason.(int))
}
<commit_msg>Handle RPC call (TODO: add rpc handlers registration)<commit_after>package node

import (
	"erlang/term"
)

type rexRPC struct {
	gsi *GenServerImpl
}

func (nk *rexRPC) Behaviour() (Behaviour, map[string]interface{}) {
	nk.gsi = &GenServerImpl{}
	return nk.gsi, nk.gsi.Options()
}

func (nk *rexRPC) Init(args ...interface{}) {
	nLog("REX: Init: %#v", args)
}

func (nk *rexRPC) HandleCast(message *term.Term) {
	nLog("REX: HandleCast: %#v", *message)
}

func (nk *rexRPC) HandleCall(message *term.Term, from *term.Tuple) (reply *term.Term) {
	nLog("REX: HandleCall: %#v, From: %#v", *message, *from)
	switch req := (*message).(type) {
	case term.Tuple:
		if len(req) > 0 {
			switch act := req[0].(type) {
			case term.Atom:
				if string(act) == "call" {
					nLog("RPC CALL: Module: %#v, Function: %#v, Args: %#v, GroupLeader: %#v", req[1], req[2], req[3], req[4])
					replyTerm := term.Term(term.Tuple{req[1], req[2]})
					reply = &replyTerm
				}
			}
		}
	}
	if reply == nil {
		replyTerm := term.Term(term.Tuple{term.Atom("badrpc"), term.Atom("unknown")})
		reply = &replyTerm
	}
	return
}

func (nk *rexRPC) HandleInfo(message *term.Term) {
	nLog("REX: HandleInfo: %#v", *message)
}

func (nk *rexRPC) Terminate(reason interface{}) {
	nLog("REX: Terminate: %#v", reason.(int))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type conf struct {
	GraphiteHost string
	RedisHost    string
	Interval     string
	Prefix       string
	Daemon       bool
	interval     time.Duration
}

func (c *conf) setFlags() {
	defaultGraphite := "localhost:2003"
	defaultRedis := "localhost:6379"
	defaultInterval := "10s"
	defaultPrefix := "redis.$host"
	if e := os.Getenv("GRAPHITE_HOST"); e != "" {
		defaultGraphite = e
	}
	if e := os.Getenv("REDIS_HOST"); e != "" {
		defaultRedis = e
	}
	if e := os.Getenv("MONITOR_INTERVAL"); e != "" {
		defaultInterval = e
	}
	if e := os.Getenv("MONITOR_PREFIX"); e != "" {
		defaultPrefix = e
	}

	flag.StringVar(&(c.GraphiteHost), "graphite", defaultGraphite, "Grahite Host Url (host:port)")
	flag.StringVar(&(c.RedisHost), "redis", defaultRedis, "Redis Instance (host:port,host:port,host:port...)")
	flag.StringVar(&(c.Interval), "interval", defaultInterval, "Metrics send interval (only valid if daemon = true)")
	flag.StringVar(&(c.Prefix), "prefix", defaultPrefix, "Metrics prefix")
	flag.BoolVar(&(c.Daemon), "daemon", false, "Daemonize and report every [interval] seconds")
}

func (c *conf) GetPrefix(Host string) string {
	prefix := c.Prefix
	host := strings.Replace(Host, ".", "_", -1)
	prefix = strings.Replace(prefix, "$host", host, -1)
	return prefix
}

type Reporter interface {
	Report(*conf, string, RedisStats)
}

type GraphiteReporter struct{}

func (g *GraphiteReporter) Report(cfg *conf, host string, stats RedisStats) {
	prefix := cfg.GetPrefix(host)
	if len(prefix) > 0 && !strings.HasSuffix(prefix, ".") {
		prefix = prefix + "."
	}
	reportTime := time.Now()
	if conn, err := net.Dial("tcp", cfg.GraphiteHost); err == nil {
		defer conn.Close()
		if conn, ok := conn.(*net.TCPConn); ok {
			conn.SetNoDelay(false)
		}
		report := func(name string, value string) {
			if _, err := conn.Write([]byte(name + " " + value + " " + strconv.Itoa(int(reportTime.Unix())) + "\n")); err != nil {
				log.Println("Failed to send stats to graphite @ %s. Error: %s", cfg.GraphiteHost, err.Error())
			}
		}
		for section, values := range stats {
			sectionPrefix := strings.ToLower(section) + "."
			switch section {
			case "Clients", "Memory", "Persistence", "Stats":
				for name, metricValue := range values {
					metricName := prefix + sectionPrefix + name
					report(metricName, metricValue)
				}
			case "Keyspace":
				for db, value := range values {
					dbPrefix := sectionPrefix + db + "."
					vars := strings.Split(value, ",")
					for _, v := range vars {
						if val := strings.Split(v, "="); len(val) == 2 {
							metricName := prefix + dbPrefix + val[0]
							report(metricName, val[1])
						}
					}
				}
			}
		}
	} else {
		log.Printf("Failed to connect to graphite @ %s. Error: %s", cfg.GraphiteHost, err.Error())
	}
}

type RedisStats map[string]map[string]string

func QueryStats(host string) RedisStats {
	if c, err := redis.Dial("tcp", host); err == nil {
		defer c.Close()
		if stats, err := redis.String(c.Do("INFO")); err == nil {
			lines := strings.Split(stats, "\r\n")
			rs := RedisStats(make(map[string]map[string]string))
			var wg map[string]string
			for _, l := range lines {
				if len(l) == 0 {
					wg = nil
					continue
				} else if strings.HasPrefix(l, "#") {
					k := strings.TrimSpace(strings.TrimPrefix(l, "#"))
					wg = make(map[string]string)
					rs[k] = wg
				} else if wg != nil {
					if values := strings.Split(l, ":"); len(values) == 2 {
						if _, err := strconv.ParseFloat(values[1], 64); err == nil {
							switch values[0] {
							case "redis_git_sha1", "redis_git_dirty", "redis_build_id", "arch_bits",
								"process_id", "tcp_port", "aof_enabled":
								// don't report these metrics
								continue
							default:
								wg[values[0]] = values[1]
							}
						}
					}
				}
			}
			return rs
		} else {
			log.Printf("Failed to query stats from redis @ %s. Error: %s", host, err.Error())
			return nil
		}
	} else {
		log.Printf("Failed to connect to redis @ %s. Error: %s", host, err.Error())
		return nil
	}
}

func ctrlc(stop chan<- bool) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go func() {
		forceExit := false
		for _ = range c {
			if forceExit {
				os.Exit(2)
			} else {
				go func() {
					close(stop)
				}()
				forceExit = true
			}
		}
	}()
}

func run(cfg *conf) {
	redisHosts := strings.Split(cfg.RedisHost, ",")
	var reporter Reporter
	reporter = &GraphiteReporter{}
	for _, rhost := range redisHosts {
		if stats := QueryStats(rhost); stats != nil {
			if strings.HasSuffix(rhost, ":6379") {
				rhost = strings.TrimSuffix(rhost, ":6379")
			}
			reporter.Report(cfg, rhost, stats)
		}
	}
}

func daemon(cfg *conf, stop <-chan bool) {
	run(cfg)
	ticker := time.NewTicker(cfg.interval)
	for {
		select {
		case <-ticker.C:
			run(cfg)
		case <-stop:
			return
		}
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	fc := new(conf)
	fc.setFlags()
	flag.Parse()
	if fc.Daemon {
		if d, err := time.ParseDuration(fc.Interval); err == nil {
			fc.interval = d
		} else {
			fmt.Printf("ERROR: Failed to parse duration %s (%s)\n", fc.Interval, err.Error())
			os.Exit(2)
		}
	}

	fmt.Print("Redis Monitor --==--> Graphite\n")
	fmt.Print("\n")
	fmt.Println("[-] Graphite Host:\t" + fc.GraphiteHost + "\n" +
		"[-] Redis Host:\t" + fc.RedisHost + "\n" +
		"[-] Interval:\t" + fc.Interval + "\n" +
		"[-] Prefix:\t" + fc.Prefix)

	stop := make(chan bool)
	ctrlc(stop)

	if fc.Daemon {
		fmt.Println("[-] Running...")
		daemon(fc, stop)
		fmt.Println("[-] Stopped")
	} else {
		run(fc)
	}
}
<commit_msg>Fix up keyspace reporting<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type conf struct {
	GraphiteHost string
	RedisHost    string
	Interval     string
	Prefix       string
	Daemon       bool
	interval     time.Duration
}

func (c *conf) setFlags() {
	defaultGraphite := "localhost:2003"
	defaultRedis := "localhost:6379"
	defaultInterval := "10s"
	defaultPrefix := "redis.$host"
	defaultDaemon := false
	if e := os.Getenv("GRAPHITE_HOST"); e != "" {
		defaultGraphite = e
	}
	if e := os.Getenv("REDIS_HOST"); e != "" {
		defaultRedis = e
	}
	if e := os.Getenv("MONITOR_INTERVAL"); e != "" {
		defaultInterval = e
	}
	if e := os.Getenv("MONITOR_PREFIX"); e != "" {
		defaultPrefix = e
	}
	if e := os.Getenv("MONITOR_DAEMON"); e != "" {
		defaultDaemon = true
	}

	flag.StringVar(&(c.GraphiteHost), "graphite", defaultGraphite, "Grahite Host Url (host:port)")
	flag.StringVar(&(c.RedisHost), "redis", defaultRedis, "Redis Instance (host:port,host:port,host:port...)")
	flag.StringVar(&(c.Interval), "interval", defaultInterval, "Metrics send interval (only valid if daemon = true)")
	flag.StringVar(&(c.Prefix), "prefix", defaultPrefix, "Metrics prefix")
	flag.BoolVar(&(c.Daemon), "daemon", defaultDaemon, "Daemonize and report every [interval] seconds")
}

func (c *conf) GetPrefix(Host string) string {
	prefix := c.Prefix
	host := strings.Replace(Host, ".", "_", -1)
	prefix = strings.Replace(prefix, "$host", host, -1)
	return prefix
}

type Reporter interface {
	Report(*conf, string, RedisStats)
}

type GraphiteReporter struct{}

func (g *GraphiteReporter) Report(cfg *conf, host string, stats RedisStats) {
	prefix := cfg.GetPrefix(host)
	if len(prefix) > 0 && !strings.HasSuffix(prefix, ".") {
		prefix = prefix + "."
	}
	reportTime := time.Now()
	if conn, err := net.Dial("tcp", cfg.GraphiteHost); err == nil {
		defer conn.Close()
		if conn, ok := conn.(*net.TCPConn); ok {
			conn.SetNoDelay(false)
		}
		report := func(name string, value string) {
			if _, err := conn.Write([]byte(name + " " + value + " " + strconv.Itoa(int(reportTime.Unix())) + "\n")); err != nil {
				log.Println("Failed to send stats to graphite @ %s. Error: %s", cfg.GraphiteHost, err.Error())
			}
		}
		for section, values := range stats {
			sectionPrefix := strings.ToLower(section) + "."
			switch section {
			case "Clients", "Memory", "Persistence", "Stats", "Keyspace":
				for name, metricValue := range values {
					metricName := prefix + sectionPrefix + name
					report(metricName, metricValue)
				}
			}
		}
	} else {
		log.Printf("Failed to connect to graphite @ %s. Error: %s", cfg.GraphiteHost, err.Error())
	}
}

type RedisStats map[string]map[string]string

func QueryStats(host string) RedisStats {
	if c, err := redis.Dial("tcp", host); err == nil {
		defer c.Close()
		if stats, err := redis.String(c.Do("INFO")); err == nil {
			lines := strings.Split(stats, "\r\n")
			rs := RedisStats(make(map[string]map[string]string))
			var wg map[string]string
			var section string
			for _, l := range lines {
				if len(l) == 0 {
					wg = nil
					continue
				} else if strings.HasPrefix(l, "#") {
					k := strings.TrimSpace(strings.TrimPrefix(l, "#"))
					wg = make(map[string]string)
					rs[k] = wg
					section = k
				} else if wg != nil {
					if values := strings.Split(l, ":"); len(values) == 2 {
						if section == "Keyspace" {
							csv := strings.Split(values[1], ",")
							for _, query := range csv {
								if kvs := strings.Split(query, "="); len(kvs) == 2 {
									if _, err := strconv.ParseFloat(kvs[1], 64); err == nil {
										wg[values[0]+"."+kvs[0]] = kvs[1]
									}
								}
							}
						} else {
							if _, err := strconv.ParseFloat(values[1], 64); err == nil {
								switch values[0] {
								case "redis_git_sha1", "redis_git_dirty", "redis_build_id", "arch_bits",
									"process_id", "tcp_port", "aof_enabled":
									// don't report these metrics
									continue
								default:
									wg[values[0]] = values[1]
								}
							}
						}
					}
				}
			}
			return rs
		} else {
			log.Printf("Failed to query stats from redis @ %s. Error: %s", host, err.Error())
			return nil
		}
	} else {
		log.Printf("Failed to connect to redis @ %s. Error: %s", host, err.Error())
		return nil
	}
}

func ctrlc(stop chan<- bool) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go func() {
		forceExit := false
		for _ = range c {
			if forceExit {
				os.Exit(2)
			} else {
				go func() {
					close(stop)
				}()
				forceExit = true
			}
		}
	}()
}

func run(cfg *conf) {
	redisHosts := strings.Split(cfg.RedisHost, ",")
	var reporter Reporter
	reporter = &GraphiteReporter{}
	for _, rhost := range redisHosts {
		if stats := QueryStats(rhost); stats != nil {
			if strings.HasSuffix(rhost, ":6379") {
				rhost = strings.TrimSuffix(rhost, ":6379")
			}
			reporter.Report(cfg, rhost, stats)
		}
	}
}

func daemon(cfg *conf, stop <-chan bool) {
	run(cfg)
	ticker := time.NewTicker(cfg.interval)
	for {
		select {
		case <-ticker.C:
			run(cfg)
		case <-stop:
			return
		}
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	fc := new(conf)
	fc.setFlags()
	flag.Parse()
	if fc.Daemon {
		if d, err := time.ParseDuration(fc.Interval); err == nil {
			fc.interval = d
		} else {
			fmt.Printf("ERROR: Failed to parse duration %s (%s)\n", fc.Interval, err.Error())
			os.Exit(2)
		}
	}

	fmt.Print("Redis Monitor --==--> Graphite\n")
	fmt.Print("\n")
	fmt.Println("[-] Graphite Host:\t" + fc.GraphiteHost + "\n" +
		"[-] Redis Host:\t" + fc.RedisHost + "\n" +
		"[-] Interval:\t" + fc.Interval + "\n" +
		"[-] Prefix:\t" + fc.Prefix)

	stop := make(chan bool)
	ctrlc(stop)

	if fc.Daemon {
		fmt.Println("[-] Running...")
		daemon(fc, stop)
		fmt.Println("[-] Stopped")
	} else {
		run(fc)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 bee 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 main

import (
	"io/ioutil"
	"os"
	path "path/filepath"
	"runtime"
	"strings"
)

var cmdRun = &Command{
	UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true]  [-gendoc=true]",
	Short:     "run the app which can hot compile",
	Long: `
start the appname throw exec.Command

then start a inotify watch for current dir

when the file has changed bee will auto go build and restart the app

	file changed
	     |
  check if it's go file
	     |
     yes     no
      |       |
 go build    do nothing
     |
 restart app
`,
}

var mainFiles ListOpts

var downdoc docValue
var gendoc docValue

func init() {
	cmdRun.Run = runApp
	cmdRun.Flag.Var(&mainFiles, "main", "specify main go files")
	cmdRun.Flag.Var(&gendoc, "gendoc", "auto generate the docs")
	cmdRun.Flag.Var(&downdoc, "downdoc", "auto download swagger file when not exist")
}

var appname string

func runApp(cmd *Command, args []string) int {
	exit := make(chan bool)
	crupath, _ := os.Getwd()

	if len(args) == 0 || args[0] == "watchall" {
		appname = path.Base(crupath)
		ColorLog("[INFO] Uses '%s' as 'appname'\n", appname)
	} else {
		appname = args[0]
	}
	Debugf("current path:%s\n", crupath)

	err := loadConfig()
	if err != nil {
		ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
	}

	var paths []string

	readAppDirectories(crupath, &paths)

	// Because monitor files has some issues, we watch current directory
	// and ignore non-go files.
	gps := GetGOPATHs()
	if len(gps) == 0 {
		ColorLog("[ERRO] Fail to start[ %s ]\n", "$GOPATH is not set or empty")
		os.Exit(2)
	}
	gopath := gps[0]
	for _, p := range conf.DirStruct.Others {
		paths = append(paths, strings.Replace(p, "$GOPATH", gopath, -1))
	}

	files := []string{}
	for _, arg := range mainFiles {
		if len(arg) > 0 {
			files = append(files, arg)
		}
	}

	if gendoc == "true" {
		NewWatcher(paths, files, true)
		Autobuild(files, true)
	} else {
		NewWatcher(paths, files, false)
		Autobuild(files, false)
	}
	if downdoc == "true" {
		if _, err := os.Stat(path.Join(crupath, "swagger")); err != nil {
			if os.IsNotExist(err) {
				downloadFromUrl(swaggerlink, "swagger.zip")
				unzipAndDelete("swagger.zip", "swagger")
			}
		}
	}
	for {
		select {
		case <-exit:
			runtime.Goexit()
		}
	}
	return 0
}

func readAppDirectories(directory string, paths *[]string) {
	fileInfos, err := ioutil.ReadDir(directory)
	if err != nil {
		return
	}

	useDiectory := false
	for _, fileInfo := range fileInfos {
		if strings.HasSuffix(fileInfo.Name(), "docs") {
			continue
		}
		if fileInfo.IsDir() == true && fileInfo.Name()[0] != '.' {
			readAppDirectories(directory+"/"+fileInfo.Name(), paths)
			continue
		}

		if useDiectory == true {
			continue
		}

		if path.Ext(fileInfo.Name()) == ".go" {
			*paths = append(*paths, directory)
			useDiectory = true
		}
	}

	return
}
<commit_msg>Fix  Spelling mistake<commit_after>// Copyright 2013 bee 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 main

import (
	"io/ioutil"
	"os"
	path "path/filepath"
	"runtime"
	"strings"
)

var cmdRun = &Command{
	UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true]  [-gendoc=true]",
	Short:     "run the app which can hot compile",
	Long: `
start the appname throw exec.Command

then start a inotify watch for current dir

when the file has changed bee will auto go build and restart the app

	file changed
	     |
  check if it's go file
	     |
     yes     no
      |       |
 go build    do nothing
     |
 restart app
`,
}

var mainFiles ListOpts

var downdoc docValue
var gendoc docValue

func init() {
	cmdRun.Run = runApp
	cmdRun.Flag.Var(&mainFiles, "main", "specify main go files")
	cmdRun.Flag.Var(&gendoc, "gendoc", "auto generate the docs")
	cmdRun.Flag.Var(&downdoc, "downdoc", "auto download swagger file when not exist")
}

var appname string

func runApp(cmd *Command, args []string) int {
	exit := make(chan bool)
	crupath, _ := os.Getwd()

	if len(args) == 0 || args[0] == "watchall" {
		appname = path.Base(crupath)
		ColorLog("[INFO] Uses '%s' as 'appname'\n", appname)
	} else {
		appname = args[0]
	}
	Debugf("current path:%s\n", crupath)

	err := loadConfig()
	if err != nil {
		ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
	}

	var paths []string

	readAppDirectories(crupath, &paths)

	// Because monitor files has some issues, we watch current directory
	// and ignore non-go files.
	gps := GetGOPATHs()
	if len(gps) == 0 {
		ColorLog("[ERRO] Fail to start[ %s ]\n", "$GOPATH is not set or empty")
		os.Exit(2)
	}
	gopath := gps[0]
	for _, p := range conf.DirStruct.Others {
		paths = append(paths, strings.Replace(p, "$GOPATH", gopath, -1))
	}

	files := []string{}
	for _, arg := range mainFiles {
		if len(arg) > 0 {
			files = append(files, arg)
		}
	}

	if gendoc == "true" {
		NewWatcher(paths, files, true)
		Autobuild(files, true)
	} else {
		NewWatcher(paths, files, false)
		Autobuild(files, false)
	}
	if downdoc == "true" {
		if _, err := os.Stat(path.Join(crupath, "swagger")); err != nil {
			if os.IsNotExist(err) {
				downloadFromUrl(swaggerlink, "swagger.zip")
				unzipAndDelete("swagger.zip", "swagger")
			}
		}
	}
	for {
		select {
		case <-exit:
			runtime.Goexit()
		}
	}
	return 0
}

func readAppDirectories(directory string, paths *[]string) {
	fileInfos, err := ioutil.ReadDir(directory)
	if err != nil {
		return
	}

	useDirectory := false
	for _, fileInfo := range fileInfos {
		if strings.HasSuffix(fileInfo.Name(), "docs") {
			continue
		}
		if fileInfo.IsDir() == true && fileInfo.Name()[0] != '.' {
			readAppDirectories(directory+"/"+fileInfo.Name(), paths)
			continue
		}

		if useDirectory == true {
			continue
		}

		if path.Ext(fileInfo.Name()) == ".go" {
			*paths = append(*paths, directory)
			useDirectory = true
		}
	}

	return
}
<|endoftext|>