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

package factom

import (
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
)

var (
	ErrECIDUndefined = errors.New("ECID type undefined")
)

// ECID defines the type of an Entry Credit Block Entry
type ECID byte

// Available ECID types
const (
	ECIDServerIndexNumber ECID = iota // 0
	ECIDMinuteNumber                  // 1
	ECIDChainCommit                   // 2
	ECIDEntryCommit                   // 3
	ECIDBalanceIncrease               // 4
)

func (id ECID) String() string {
	switch id {
	case ECIDServerIndexNumber:
		return "ServerIndexNumber"
	case ECIDMinuteNumber:
		return "MinuteNumber"
	case ECIDChainCommit:
		return "ChainCommit"
	case ECIDEntryCommit:
		return "EntryCommit"
	case ECIDBalanceIncrease:
		return "BalanceIncrease"
	default:
		return "ECIDUndefined"
	}
}

// ECBlock (Entry Credit Block) holds transactions that create Chains and
// Entries, and fund Entry Credit Addresses.
type ECBlock struct {
	Header struct {
		BodyHash       string `json:"bodyhash"`
		PrevHeaderHash string `json:"prevheaderhash"`
		PrevFullHash   string `json:"prevfullhash"`
		DBHeight       int64  `json:"dbheight"`
	} `json:"header"`
	HeaderHash string     `json:"headerhash"`
	FullHash   string     `json:"fullhash"`
	Entries    []ECBEntry `json:"body"`
}

func (e *ECBlock) String() string {
	var s string

	s += fmt.Sprintln("HeaderHash:", e.HeaderHash)
	s += fmt.Sprintln("PrevHeaderHash:", e.Header.PrevHeaderHash)
	s += fmt.Sprintln("FullHash:", e.FullHash)
	s += fmt.Sprintln("PrevFullHash:", e.Header.PrevFullHash)
	s += fmt.Sprintln("BodyHash:", e.Header.BodyHash)
	s += fmt.Sprintln("DBHeight:", e.Header.DBHeight)

	s += fmt.Sprintln("Entries:")
	for _, v := range e.Entries {
		s += fmt.Sprintln(v)
	}

	return s
}

func (e *ECBlock) UnmarshalJSON(js []byte) error {
	tmp := new(struct {
		Header struct {
			BodyHash       string `json:"bodyhash"`
			PrevHeaderHash string `json:"prevheaderhash"`
			PrevFullHash   string `json:"prevfullhash"`
			DBHeight       int64  `json:"dbheight"`
		} `json:"header"`
		HeaderHash string `json:"headerhash"`
		FullHash   string `json:"fullhash"`
		Body       struct {
			Entries []json.RawMessage `json:"entries"`
		} `json:"body"`
	})

	err := json.Unmarshal(js, tmp)
	if err != nil {
		return err
	}

	e.Header.BodyHash = tmp.Header.BodyHash
	e.Header.PrevHeaderHash = tmp.Header.PrevHeaderHash
	e.Header.PrevFullHash = tmp.Header.PrevFullHash
	e.Header.DBHeight = tmp.Header.DBHeight
	e.HeaderHash = tmp.HeaderHash
	e.FullHash = tmp.FullHash
	for _, v := range tmp.Body.Entries {
		switch {
		case regexp.MustCompile(`"number":`).MatchString(string(v)):
			a := new(MinuteNumber)
			err := json.Unmarshal(v, a)
			if err != nil {
				return err
			}
			e.Entries = append(e.Entries, a)
		case regexp.MustCompile(`"serverindexnumber":`).MatchString(string(v)):
			a := new(ServerIndexNumber)
			err := json.Unmarshal(v, a)
			if err != nil {
				return err
			}
			e.Entries = append(e.Entries, a)
		case regexp.MustCompile(`"entryhash":`).MatchString(string(v)):
			if regexp.MustCompile(`"chainidhash":`).MatchString(string(v)) {
				a := new(ChainCommit)
				err := json.Unmarshal(v, a)
				if err != nil {
					return err
				}
				e.Entries = append(e.Entries, a)

			} else {
				a := new(EntryCommit)
				err := json.Unmarshal(v, a)
				if err != nil {
					return err
				}
				e.Entries = append(e.Entries, a)
			}
		default:
		}
	}

	return nil
}

// Entry Credit Block Entries are individual members of the Entry Credit Block.
type ECBEntry interface {
	Type() ECID
	String() string
}

type ServerIndexNumber struct {
	ServerIndexNumber int `json:"serverindexnumber"`
}

func (i *ServerIndexNumber) Type() ECID {
	return ECIDServerIndexNumber
}

func (i *ServerIndexNumber) String() string {
	return fmt.Sprintln("ServerIndexNumber:", i.ServerIndexNumber)
}

type MinuteNumber struct {
	Number int `json:"number"`
}

func (m *MinuteNumber) Type() ECID {
	return ECIDMinuteNumber
}

func (m *MinuteNumber) String() string {
	return fmt.Sprintln("MinuteNumber:", m.Number)
}

type ChainCommit struct {
	Version     int    `json:"version"`
	MilliTime   int64  `json:"millitime"`
	ChainIDHash string `json:"chainidhash"`
	Weld        string `json:"weld"`
	EntryHash   string `json:"entryhash"`
	Credits     int    `json:"credits"`
	ECPubKey    string `json:"ecpubkey"`
	Sig         string `json:"sig"`
}

// TODO: func (c *ChainCommit) UnmarshalJSON(js []byte) error {

func (c *ChainCommit) Type() ECID {
	return ECIDChainCommit
}

func (c *ChainCommit) String() string {
	var s string

	s += fmt.Sprintln("ChainCommit {")
	s += fmt.Sprintln("	Version:", c.Version)
	s += fmt.Sprintln("	Millitime:", c.MilliTime)
	s += fmt.Sprintln("	ChainIDHash:", c.ChainIDHash)
	s += fmt.Sprintln("	Weld:", c.Weld)
	s += fmt.Sprintln("	EntryHash:", c.EntryHash)
	s += fmt.Sprintln("	Credits:", c.Credits)
	s += fmt.Sprintln("	ECPubKey:", c.ECPubKey)
	s += fmt.Sprintln("	Signature:", c.Sig)
	s += fmt.Sprintln("}")

	return s
}

type EntryCommit struct {
	Version   int    `json:"version"`
	MilliTime int64  `json:"millitime"`
	EntryHash string `json:"entryhash"`
	Credits   int    `json:"credits"`
	ECPubKey  string `json:"ecpubkey"`
	Sig       string `json:"sig"`
}

func (e *EntryCommit) UnmarshalJSON(js []byte) error {
	tmp := new(struct {
		Version   int    `json:"version"`
		MilliTime string `json:"millitime"`
		EntryHash string `json:"entryhash"`
		Credits   int    `json:"credits"`
		ECPubKey  string `json:"ecpubkey"`
		Sig       string `json:"sig"`
	})

	err := json.Unmarshal(js, tmp)
	if err != nil {
		return err
	}

	m := make([]byte, 8)
	if p, err := hex.DecodeString(tmp.MilliTime); err != nil {
		return err
	} else {
		copy(m, p)
	}
	e.MilliTime = int64(binary.BigEndian.Uint64(m))

	e.Version = tmp.Version
	e.EntryHash = tmp.EntryHash
	e.Credits = tmp.Credits
	e.ECPubKey = tmp.ECPubKey
	e.Sig = tmp.Sig

	return nil
}

func (e *EntryCommit) Type() ECID {
	return ECIDEntryCommit
}

func (e *EntryCommit) String() string {
	var s string

	s += fmt.Sprintln("EntryCommit {")
	s += fmt.Sprintln("	Version:", e.Version)
	s += fmt.Sprintln("	Millitime:", e.MilliTime)
	s += fmt.Sprintln("	EntryHash:", e.EntryHash)
	s += fmt.Sprintln("	Credits:", e.Credits)
	s += fmt.Sprintln("	ECPubKey:", e.ECPubKey)
	s += fmt.Sprintln("	Signature:", e.Sig)
	s += fmt.Sprintln("}")

	return s
}

func GetECBlock(keymr string) (*ECBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("entrycredit-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	// create a wraper construct for the ECBlock API return
	wrap := new(struct {
		ECBlock *ECBlock `json:"ecblock"`
	})
	if err := json.Unmarshal(resp.JSONResult(), wrap); err != nil {
		return nil, err
	}

	return wrap.ECBlock, nil
}
<commit_msg>fixed millitime conversion for ecblock entrycommit<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
)

var (
	ErrECIDUndefined = errors.New("ECID type undefined")
)

// ECID defines the type of an Entry Credit Block Entry
type ECID byte

// Available ECID types
const (
	ECIDServerIndexNumber ECID = iota // 0
	ECIDMinuteNumber                  // 1
	ECIDChainCommit                   // 2
	ECIDEntryCommit                   // 3
	ECIDBalanceIncrease               // 4
)

func (id ECID) String() string {
	switch id {
	case ECIDServerIndexNumber:
		return "ServerIndexNumber"
	case ECIDMinuteNumber:
		return "MinuteNumber"
	case ECIDChainCommit:
		return "ChainCommit"
	case ECIDEntryCommit:
		return "EntryCommit"
	case ECIDBalanceIncrease:
		return "BalanceIncrease"
	default:
		return "ECIDUndefined"
	}
}

// ECBlock (Entry Credit Block) holds transactions that create Chains and
// Entries, and fund Entry Credit Addresses.
type ECBlock struct {
	Header struct {
		BodyHash       string `json:"bodyhash"`
		PrevHeaderHash string `json:"prevheaderhash"`
		PrevFullHash   string `json:"prevfullhash"`
		DBHeight       int64  `json:"dbheight"`
	} `json:"header"`
	HeaderHash string     `json:"headerhash"`
	FullHash   string     `json:"fullhash"`
	Entries    []ECBEntry `json:"body"`
}

func (e *ECBlock) String() string {
	var s string

	s += fmt.Sprintln("HeaderHash:", e.HeaderHash)
	s += fmt.Sprintln("PrevHeaderHash:", e.Header.PrevHeaderHash)
	s += fmt.Sprintln("FullHash:", e.FullHash)
	s += fmt.Sprintln("PrevFullHash:", e.Header.PrevFullHash)
	s += fmt.Sprintln("BodyHash:", e.Header.BodyHash)
	s += fmt.Sprintln("DBHeight:", e.Header.DBHeight)

	s += fmt.Sprintln("Entries:")
	for _, v := range e.Entries {
		s += fmt.Sprintln(v)
	}

	return s
}

func (e *ECBlock) UnmarshalJSON(js []byte) error {
	tmp := new(struct {
		Header struct {
			BodyHash       string `json:"bodyhash"`
			PrevHeaderHash string `json:"prevheaderhash"`
			PrevFullHash   string `json:"prevfullhash"`
			DBHeight       int64  `json:"dbheight"`
		} `json:"header"`
		HeaderHash string `json:"headerhash"`
		FullHash   string `json:"fullhash"`
		Body       struct {
			Entries []json.RawMessage `json:"entries"`
		} `json:"body"`
	})

	err := json.Unmarshal(js, tmp)
	if err != nil {
		return err
	}

	e.Header.BodyHash = tmp.Header.BodyHash
	e.Header.PrevHeaderHash = tmp.Header.PrevHeaderHash
	e.Header.PrevFullHash = tmp.Header.PrevFullHash
	e.Header.DBHeight = tmp.Header.DBHeight
	e.HeaderHash = tmp.HeaderHash
	e.FullHash = tmp.FullHash
	for _, v := range tmp.Body.Entries {
		switch {
		case regexp.MustCompile(`"number":`).MatchString(string(v)):
			a := new(MinuteNumber)
			err := json.Unmarshal(v, a)
			if err != nil {
				return err
			}
			e.Entries = append(e.Entries, a)
		case regexp.MustCompile(`"serverindexnumber":`).MatchString(string(v)):
			a := new(ServerIndexNumber)
			err := json.Unmarshal(v, a)
			if err != nil {
				return err
			}
			e.Entries = append(e.Entries, a)
		case regexp.MustCompile(`"entryhash":`).MatchString(string(v)):
			if regexp.MustCompile(`"chainidhash":`).MatchString(string(v)) {
				a := new(ChainCommit)
				err := json.Unmarshal(v, a)
				if err != nil {
					return err
				}
				e.Entries = append(e.Entries, a)

			} else {
				a := new(EntryCommit)
				err := json.Unmarshal(v, a)
				if err != nil {
					return err
				}
				e.Entries = append(e.Entries, a)
			}
		default:
		}
	}

	return nil
}

// Entry Credit Block Entries are individual members of the Entry Credit Block.
type ECBEntry interface {
	Type() ECID
	String() string
}

type ServerIndexNumber struct {
	ServerIndexNumber int `json:"serverindexnumber"`
}

func (i *ServerIndexNumber) Type() ECID {
	return ECIDServerIndexNumber
}

func (i *ServerIndexNumber) String() string {
	return fmt.Sprintln("ServerIndexNumber:", i.ServerIndexNumber)
}

type MinuteNumber struct {
	Number int `json:"number"`
}

func (m *MinuteNumber) Type() ECID {
	return ECIDMinuteNumber
}

func (m *MinuteNumber) String() string {
	return fmt.Sprintln("MinuteNumber:", m.Number)
}

type ChainCommit struct {
	Version     int    `json:"version"`
	MilliTime   int64  `json:"millitime"`
	ChainIDHash string `json:"chainidhash"`
	Weld        string `json:"weld"`
	EntryHash   string `json:"entryhash"`
	Credits     int    `json:"credits"`
	ECPubKey    string `json:"ecpubkey"`
	Sig         string `json:"sig"`
}

// TODO: func (c *ChainCommit) UnmarshalJSON(js []byte) error {

func (c *ChainCommit) Type() ECID {
	return ECIDChainCommit
}

func (c *ChainCommit) String() string {
	var s string

	s += fmt.Sprintln("ChainCommit {")
	s += fmt.Sprintln("	Version:", c.Version)
	s += fmt.Sprintln("	Millitime:", c.MilliTime)
	s += fmt.Sprintln("	ChainIDHash:", c.ChainIDHash)
	s += fmt.Sprintln("	Weld:", c.Weld)
	s += fmt.Sprintln("	EntryHash:", c.EntryHash)
	s += fmt.Sprintln("	Credits:", c.Credits)
	s += fmt.Sprintln("	ECPubKey:", c.ECPubKey)
	s += fmt.Sprintln("	Signature:", c.Sig)
	s += fmt.Sprintln("}")

	return s
}

type EntryCommit struct {
	Version   int    `json:"version"`
	MilliTime int64  `json:"millitime"`
	EntryHash string `json:"entryhash"`
	Credits   int    `json:"credits"`
	ECPubKey  string `json:"ecpubkey"`
	Sig       string `json:"sig"`
}

func (e *EntryCommit) UnmarshalJSON(js []byte) error {
	tmp := new(struct {
		Version   int    `json:"version"`
		MilliTime string `json:"millitime"`
		EntryHash string `json:"entryhash"`
		Credits   int    `json:"credits"`
		ECPubKey  string `json:"ecpubkey"`
		Sig       string `json:"sig"`
	})

	err := json.Unmarshal(js, tmp)
	if err != nil {
		return err
	}

	// convert 6 byte MilliTime into int64
	m := make([]byte, 8)
	if p, err := hex.DecodeString(tmp.MilliTime); err != nil {
		return err
	} else {
		// copy p into the last 6 bytes
		copy(m[2:], p)
	}
	fmt.Printf("DEBUG: converting millitime %x\n", m)
	e.MilliTime = int64(binary.BigEndian.Uint64(m))

	e.Version = tmp.Version
	e.EntryHash = tmp.EntryHash
	e.Credits = tmp.Credits
	e.ECPubKey = tmp.ECPubKey
	e.Sig = tmp.Sig

	return nil
}

func (e *EntryCommit) Type() ECID {
	return ECIDEntryCommit
}

func (e *EntryCommit) String() string {
	var s string

	s += fmt.Sprintln("EntryCommit {")
	s += fmt.Sprintln("	Version:", e.Version)
	s += fmt.Sprintln("	Millitime:", e.MilliTime)
	s += fmt.Sprintln("	EntryHash:", e.EntryHash)
	s += fmt.Sprintln("	Credits:", e.Credits)
	s += fmt.Sprintln("	ECPubKey:", e.ECPubKey)
	s += fmt.Sprintln("	Signature:", e.Sig)
	s += fmt.Sprintln("}")

	return s
}

func GetECBlock(keymr string) (*ECBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("entrycredit-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	// create a wraper construct for the ECBlock API return
	wrap := new(struct {
		ECBlock *ECBlock `json:"ecblock"`
	})
	if err := json.Unmarshal(resp.JSONResult(), wrap); err != nil {
		return nil, err
	}

	return wrap.ECBlock, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/voxelbrain/goptions"
)

var (
	options = struct {
		Server string        `goptions:"-s, --server, description='Pixelpixel server to push to'"`
		Help   goptions.Help `goptions:"-h, --help, description='Show this help'"`
		goptions.Verbs
		Upload struct{} `goptions:"upload"`
		Logs   struct{} `goptions:"logs"`
	}{
		Server: "localhost:8080",
	}
)

const (
	keyFile = ".key"
)

func main() {
	fs := goptions.NewFlagSet("picli", &options)
	err := fs.Parse(os.Args[1:])
	key := prepareKey()

	options.Server = validateServer(options.Server)

	switch options.Verbs {
	case "upload":
		upload(key)
	case "logs":
		logs(key)
	default:
		if err != nil {
			fmt.Printf("Error: %s\n", err)
		}
		fs.PrintHelp(os.Stderr)
		return
	}

}

func makeApiCall(method, subpath string, body io.Reader) (int, string, error) {
	url := path.Join(options.Server, "pixels") + "/"
	url = slashify(url + subpath)
	req, _ := http.NewRequest(method, url, body)
	resp, err := http.DefaultClient.Do(req)
	buf := &bytes.Buffer{}

	code := -1
	if resp != nil {
		defer resp.Body.Close()
		code = resp.StatusCode
		io.Copy(buf, resp.Body)
	}

	// TODO: Sadly, this seems to be necassary. Can't seem to get it
	// working without it. I always get `malformed HTTP response ""`
	http.DefaultTransport.(*http.Transport).CloseIdleConnections()

	return code, buf.String(), err
}

func prepareKey() string {
	f, err := os.Open(keyFile)
	if err != nil {
		return ""
	}
	defer f.Close()
	key, err := ioutil.ReadAll(f)
	if err != nil {
		return ""
	}
	skey := strings.TrimSpace(string(key))
	code, _, err := makeApiCall("GET", "/"+skey, nil)
	if err == nil && code == http.StatusOK {
		return skey
	}
	return ""
}

func slashify(url string) string {
	url = path.Clean(url)
	if !strings.HasSuffix(url, "/") {
		url = url + "/"
	}
	return "http://" + strings.TrimPrefix(url, "/")
}

const (
	DEFAULT_REMOTE_SERVER = "pixelpixel.haxigon.com"
)

func validateServer(server string) string {
	resp, err := http.Get("http://" + path.Join(server, "handshake"))
	if err == nil && readAll(resp.Body) == "PIXELPIXEL OK" {
		return server
	}

	resp, err = http.Get("http://" + path.Join(DEFAULT_REMOTE_SERVER, "handshake"))
	if err == nil && readAll(resp.Body) == "PIXELPIXEL OK" {
		return DEFAULT_REMOTE_SERVER
	}
	log.Fatalf("Could not connect to server")
	return ""
}

func readAll(r io.Reader) string {
	data, _ := ioutil.ReadAll(r)
	return string(data)
}
<commit_msg>picli: Add connection timeout and proper error handling<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/voxelbrain/goptions"
)

var (
	options = struct {
		Server string        `goptions:"-s, --server, description='Pixelpixel server to push to'"`
		Help   goptions.Help `goptions:"-h, --help, description='Show this help'"`
		goptions.Verbs
		Upload struct{} `goptions:"upload"`
		Logs   struct{} `goptions:"logs"`
		Format struct{} `goptions:"format"`
	}{
		Server: "localhost:8080",
	}
)

const (
	keyFile = ".key"
)

func main() {
	fs := goptions.NewFlagSet("picli", &options)
	err := fs.Parse(os.Args[1:])
	key := prepareKey()

	switch options.Verbs {
	case "upload":
		options.Server = validateServer(options.Server)
		upload(key)
	case "logs":
		options.Server = validateServer(options.Server)
		logs(key)
	case "format":
		format()
	default:
		if err != nil {
			fmt.Printf("Error: %s\n", err)
		}
		fs.PrintHelp(os.Stderr)
		return
	}
}

func makeApiCall(method, subpath string, body io.Reader) (int, string, error) {
	url := path.Join(options.Server, "pixels") + "/"
	url = slashify(url + subpath)
	req, _ := http.NewRequest(method, url, body)
	resp, err := http.DefaultClient.Do(req)
	buf := &bytes.Buffer{}

	code := -1
	if resp != nil {
		defer resp.Body.Close()
		code = resp.StatusCode
		io.Copy(buf, resp.Body)
	}

	// TODO: Sadly, this seems to be necassary. Can't seem to get it
	// working without it. I always get `malformed HTTP response ""`
	http.DefaultTransport.(*http.Transport).CloseIdleConnections()

	return code, buf.String(), err
}

func prepareKey() string {
	f, err := os.Open(keyFile)
	if err != nil {
		return ""
	}
	defer f.Close()
	key, err := ioutil.ReadAll(f)
	if err != nil {
		return ""
	}
	skey := strings.TrimSpace(string(key))
	code, _, err := makeApiCall("GET", "/"+skey, nil)
	if err == nil && code == http.StatusOK {
		return skey
	}
	return ""
}

func slashify(url string) string {
	url = path.Clean(url)
	if !strings.HasSuffix(url, "/") {
		url = url + "/"
	}
	return "http://" + strings.TrimPrefix(url, "/")
}

const (
	DEFAULT_REMOTE_SERVER = "pixelpixel.haxigon.com"
)

func validateServer(server string) string {
	t := time.AfterFunc(3*time.Second, func() {
		log.Fatalf("Attempt to connect to server timed out")
	})
	defer func() {
		t.Stop()
	}()

	resp, err := http.Get("http://" + path.Join(server, "handshake"))
	if err == nil && readAll(resp.Body) == "PIXELPIXEL OK" {
		return server
	}

	resp, err = http.Get("http://" + path.Join(DEFAULT_REMOTE_SERVER, "handshake"))
	if err == nil && readAll(resp.Body) == "PIXELPIXEL OK" {
		return DEFAULT_REMOTE_SERVER
	}
	log.Fatalf("Could not connect to server")
	return ""
}

func readAll(r io.Reader) string {
	data, _ := ioutil.ReadAll(r)
	return string(data)
}
<|endoftext|>


<commit_before>/**
 * Copyright 2014 @ z3q.net.
 * name :
 * author : jarryliu
 * date : 2014-02-05 21:53
 * description :
 * history :
 */
package ucenter

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jsix/gof"
	"github.com/jsix/gof/web"
	"github.com/jsix/gof/web/pager"
	"go2o/src/app/front"
	"go2o/src/core/domain/interface/member"
	"go2o/src/core/infrastructure/domain"
	"go2o/src/core/infrastructure/format"
	"go2o/src/core/service/dps"
	"go2o/src/core/service/goclient"
	"go2o/src/core/variable"
	"html/template"
	"strconv"
	"strings"
)

const minAmount float64 = 50

var (
	bonusKindStr string
)

type accountC struct {
	*baseC
}

func (this *accountC) Income_log(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"partner": p,
		"member":  m,
	}, "views/ucenter/{device}/account/income_log.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Income_log_post(ctx *web.Context) {
	m := this.GetMember(ctx)
	r := ctx.Request
	r.ParseForm()
	page, _ := strconv.Atoi(r.FormValue("page"))
	size, _ := strconv.Atoi(r.FormValue("size"))

	if len(bonusKindStr) == 0 {
		bonusKindStr = strings.Join([]string{
			strconv.Itoa(member.KindBalanceTransfer),
			strconv.Itoa(member.KindBalancePresent),
			strconv.Itoa(member.KindBalanceFlow),
		}, ",")
	}

	n, rows := dps.MemberService.QueryIncomeLog(m.Id, page, size,
		" AND kind IN ("+bonusKindStr+")", "create_time DESC")
	p := pager.NewUrlPager(pager.TotalPage(n, size), page, pager.GetterJavaScriptPager)

	p.RecordCount = n
	pager := &front.Pager{Total: n, Rows: rows, Text: p.PagerString()}
	ctx.Response.JsonOutput(pager)
}

// 提现申请
func (this *accountC) Apply_cash(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)

	var latestInfo string = dps.MemberService.GetLatestApplyCashText(m.Id)
	if len(latestInfo) != 0 {
		latestInfo = "
" + latestInfo + "
"
	}

	var maxApplyAmount int
	if acc.PresentBalance < float32(minAmount) {
		maxApplyAmount = 0
	} else {
		maxApplyAmount = int(acc.PresentBalance)
	}

	var commissionStr string
	if saleConf.ApplyCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.FlowConvertCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":           conf,
		"partner":        p,
		"member":         m,
		"minAmount":      format.FormatFloat(float32(minAmount)),
		"maxApplyAmount": maxApplyAmount,
		"account":        acc,
		"latestInfo":     template.HTML(latestInfo),
		"commissionStr":  template.HTML(commissionStr),
		"presentAlias":   variable.FlowAccountAlias,
		"cns":            saleConf.ApplyCsn,
		"notSetTradePwd": len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/apply_cash.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Apply_cash_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	partnerId := this.GetPartner(ctx).Id
	amount, _ := strconv.ParseFloat(ctx.Request.FormValue("Amount"), 32)
	tradePwd := ctx.Request.FormValue("TradePwd")
	memberId := this.GetMember(ctx).Id
	saleConf := dps.PartnerService.GetSaleConf(partnerId)
	bank := dps.MemberService.GetBank(memberId)

	if bank == nil || len(bank.Account) == 0 || len(bank.AccountName) == 0 ||
		len(bank.Network) == 0 {
		err = errors.New("请先设置收款银行信息")
		goto toErr
	}

	if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err != nil {
		goto toErr
	}

	if amount < minAmount {
		err = errors.New(fmt.Sprintf("必须达到最低提现金额:%s元",
			format.FormatFloat(float32(minAmount))))
	} else {
		m := this.GetMember(ctx)
		err = dps.MemberService.SubmitApplyPresentBalance(partnerId, m.Id,
			member.TypeApplyCashToBank, float32(amount), saleConf.ApplyCsn)
	}

toErr:
	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转换活动金到提现账户
func (this *accountC) Convert_f2p(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)

	var commissionStr string
	if saleConf.FlowConvertCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.FlowConvertCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":              conf,
		"partner":           p,
		"member":            m,
		"account":           acc,
		"commissionStr":     template.HTML(commissionStr),
		"flowAlias":         variable.FlowAccountAlias,
		"flowConvertSlogan": variable.FlowConvertSlogan,
		"cns":               saleConf.FlowConvertCsn,
		"notSetTradePwd":    len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/convert_f2p.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Convert_f2p_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	partnerId := this.GetPartner(ctx).Id
	amount, _ := strconv.ParseFloat(ctx.Request.FormValue("Amount"), 32)
	tradePwd := ctx.Request.FormValue("TradePwd")
	saleConf := dps.PartnerService.GetSaleConf(partnerId)

	memberId := this.GetMember(ctx).Id

	if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err == nil {
		err = dps.MemberService.TransferFlow(memberId, member.KindBalancePresent,
			float32(amount), saleConf.FlowConvertCsn, domain.NewTradeNo(partnerId),
			fmt.Sprintf("%s转换", variable.FlowAccountAlias),
			fmt.Sprintf("%s转换%s", variable.FlowAccountAlias, variable.PresentAccountAlias))
	}

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转换活动金到提现账户
func (this *accountC) Transfer_f2m(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)

	var commissionStr string
	if saleConf.FlowConvertCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.FlowConvertCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":           conf,
		"partner":        p,
		"member":         m,
		"account":        acc,
		"commissionStr":  template.HTML(commissionStr),
		"flowAlias":      variable.FlowAccountAlias,
		"cns":            saleConf.TransCsn,
		"notSetTradePwd": len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/transfer_f2m.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Transfer_f2m_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	form := ctx.Request.Form
	partnerId := this.GetPartner(ctx).Id
	toMemberId, _ := strconv.Atoi(form.Get("ToId"))
	amount, _ := strconv.ParseFloat(form.Get("Amount"), 32)
	tradePwd := form.Get("TradePwd")
	saleConf := dps.PartnerService.GetSaleConf(partnerId)
	memberId := this.GetMember(ctx).Id

	if toMemberId == memberId {
		err = errors.New("无法转账到自己账号")
	} else {
		if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err == nil {
			err = dps.MemberService.TransferFlowTo(memberId, toMemberId, member.KindBalanceFlow,
				float32(amount), saleConf.TransCsn, domain.NewTradeNo(partnerId),
				variable.FlowAccountAlias+"转账", "转入"+variable.FlowAccountAlias)
		}
	}

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转账成功提示页面
func (this *accountC) Transfer_success(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)

	src := ctx.Request.URL.Query().Get("src")
	var title, subTitle, btnText string

	switch src {
	case "trans_f2m":
		title = "转账成功"
		subTitle = "转账成功！"
		btnText = "继续转账"
	case "convert_f2p":
		title = "转换成功"
		subTitle = variable.FlowAccountAlias + "转换成功！"
		btnText = "继续转换"
	case "apply_p2b":
		title = "申请成功"
		subTitle = "申请成功，客服将在1-3个工作日完成审核。"
		btnText = "继续提现"
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":     conf,
		"partner":  p,
		"title":    title,
		"subTitle": subTitle,
		"btnText":  btnText,
		"referer":  ctx.Request.Referer(),
	}, "views/ucenter/{device}/account/transfer_success.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Bank_info(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	bank := dps.MemberService.GetBank(m.Id)

	js, _ := json.Marshal(bank)
	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"partner": p,
		"entity":  template.JS(js),
	}, "views/ucenter/{device}/account/bank_info.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Bank_info_post(ctx *web.Context) {
	m := this.GetMember(ctx)
	r := ctx.Request
	var msg gof.Message
	r.ParseForm()
	e := new(member.BankInfo)
	web.ParseFormToEntity(r.Form, e)
	e.MemberId = m.Id
	err := dps.MemberService.SaveBankInfo(e)

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

func (this *accountC) Integral_exchange(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	acc, _ := goclient.Member.GetMemberAccount(m.Id, m.DynamicToken)

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"record":  15,
		"partner": p,
		"member":  m,
		"account": acc,
	}, "views/ucenter/{device}/account/integral_exchange.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}
<commit_msg>commit<commit_after>/**
 * Copyright 2014 @ z3q.net.
 * name :
 * author : jarryliu
 * date : 2014-02-05 21:53
 * description :
 * history :
 */
package ucenter

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jsix/gof"
	"github.com/jsix/gof/web"
	"github.com/jsix/gof/web/pager"
	"go2o/src/app/front"
	"go2o/src/core/domain/interface/member"
	"go2o/src/core/infrastructure/domain"
	"go2o/src/core/infrastructure/format"
	"go2o/src/core/service/dps"
	"go2o/src/core/service/goclient"
	"go2o/src/core/variable"
	"html/template"
	"strconv"
	"strings"
)

const minAmount float64 = 50

var (
	bonusKindStr string
)

type accountC struct {
	*baseC
}

func (this *accountC) Income_log(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"partner": p,
		"member":  m,
	}, "views/ucenter/{device}/account/income_log.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Income_log_post(ctx *web.Context) {
	m := this.GetMember(ctx)
	r := ctx.Request
	r.ParseForm()
	page, _ := strconv.Atoi(r.FormValue("page"))
	size, _ := strconv.Atoi(r.FormValue("size"))

	if len(bonusKindStr) == 0 {
		bonusKindStr = strings.Join([]string{
			strconv.Itoa(member.KindBalanceTransfer),
			strconv.Itoa(member.KindBalancePresent),
			strconv.Itoa(member.KindBalanceFlow),
		}, ",")
	}

	n, rows := dps.MemberService.QueryIncomeLog(m.Id, page, size,
		" AND kind IN ("+bonusKindStr+")", "create_time DESC")
	p := pager.NewUrlPager(pager.TotalPage(n, size), page, pager.GetterJavaScriptPager)

	p.RecordCount = n
	pager := &front.Pager{Total: n, Rows: rows, Text: p.PagerString()}
	ctx.Response.JsonOutput(pager)
}

// 提现申请
func (this *accountC) Apply_cash(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)

	var latestInfo string = dps.MemberService.GetLatestApplyCashText(m.Id)
	if len(latestInfo) != 0 {
		latestInfo = "
" + latestInfo + "
"
	}

	var maxApplyAmount int
	if acc.PresentBalance < float32(minAmount) {
		maxApplyAmount = 0
	} else {
		maxApplyAmount = int(acc.PresentBalance)
	}

	var commissionStr string
	if saleConf.ApplyCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.ApplyCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":           conf,
		"partner":        p,
		"member":         m,
		"minAmount":      format.FormatFloat(float32(minAmount)),
		"maxApplyAmount": maxApplyAmount,
		"account":        acc,
		"latestInfo":     template.HTML(latestInfo),
		"commissionStr":  template.HTML(commissionStr),
		"presentAlias":   variable.FlowAccountAlias,
		"cns":            saleConf.ApplyCsn,
		"notSetTradePwd": len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/apply_cash.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Apply_cash_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	partnerId := this.GetPartner(ctx).Id
	amount, _ := strconv.ParseFloat(ctx.Request.FormValue("Amount"), 32)
	tradePwd := ctx.Request.FormValue("TradePwd")
	memberId := this.GetMember(ctx).Id
	saleConf := dps.PartnerService.GetSaleConf(partnerId)
	bank := dps.MemberService.GetBank(memberId)

	if bank == nil || len(bank.Account) == 0 || len(bank.AccountName) == 0 ||
		len(bank.Network) == 0 {
		err = errors.New("请先设置收款银行信息")
		goto toErr
	}

	if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err != nil {
		goto toErr
	}

	if amount < minAmount {
		err = errors.New(fmt.Sprintf("必须达到最低提现金额:%s元",
			format.FormatFloat(float32(minAmount))))
	} else {
		m := this.GetMember(ctx)
		err = dps.MemberService.SubmitApplyPresentBalance(partnerId, m.Id,
			member.TypeApplyCashToBank, float32(amount), saleConf.ApplyCsn)
	}

toErr:
	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转换活动金到提现账户
func (this *accountC) Convert_f2p(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)

	var commissionStr string
	if saleConf.FlowConvertCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.FlowConvertCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":              conf,
		"partner":           p,
		"member":            m,
		"account":           acc,
		"commissionStr":     template.HTML(commissionStr),
		"flowAlias":         variable.FlowAccountAlias,
		"flowConvertSlogan": variable.FlowConvertSlogan,
		"cns":               saleConf.FlowConvertCsn,
		"notSetTradePwd":    len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/convert_f2p.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Convert_f2p_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	partnerId := this.GetPartner(ctx).Id
	amount, _ := strconv.ParseFloat(ctx.Request.FormValue("Amount"), 32)
	tradePwd := ctx.Request.FormValue("TradePwd")
	saleConf := dps.PartnerService.GetSaleConf(partnerId)

	memberId := this.GetMember(ctx).Id

	if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err == nil {
		err = dps.MemberService.TransferFlow(memberId, member.KindBalancePresent,
			float32(amount), saleConf.FlowConvertCsn, domain.NewTradeNo(partnerId),
			fmt.Sprintf("%s转换", variable.FlowAccountAlias),
			fmt.Sprintf("%s转换%s", variable.FlowAccountAlias, variable.PresentAccountAlias))
	}

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转换活动金到提现账户
func (this *accountC) Transfer_f2m(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	saleConf := dps.PartnerService.GetSaleConf(p.Id)
	m := this.GetMember(ctx)
	acc := dps.MemberService.GetAccount(m.Id)

	var commissionStr string
	if saleConf.FlowConvertCsn == 0 {
		commissionStr = "不收取手续费"
	} else {
		commissionStr = fmt.Sprintf("收取%s%s手续费",
			format.FormatFloat(saleConf.FlowConvertCsn*100), "%")
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":           conf,
		"partner":        p,
		"member":         m,
		"account":        acc,
		"commissionStr":  template.HTML(commissionStr),
		"flowAlias":      variable.FlowAccountAlias,
		"cns":            saleConf.TransCsn,
		"notSetTradePwd": len(m.TradePwd) == 0,
	}, "views/ucenter/{device}/account/transfer_f2m.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Transfer_f2m_post(ctx *web.Context) {
	var msg gof.Message
	var err error
	ctx.Request.ParseForm()
	form := ctx.Request.Form
	partnerId := this.GetPartner(ctx).Id
	toMemberId, _ := strconv.Atoi(form.Get("ToId"))
	amount, _ := strconv.ParseFloat(form.Get("Amount"), 32)
	tradePwd := form.Get("TradePwd")
	saleConf := dps.PartnerService.GetSaleConf(partnerId)
	memberId := this.GetMember(ctx).Id

	if toMemberId == memberId {
		err = errors.New("无法转账到自己账号")
	} else {
		if _, err = dps.MemberService.VerifyTradePwd(memberId, tradePwd); err == nil {
			err = dps.MemberService.TransferFlowTo(memberId, toMemberId, member.KindBalanceFlow,
				float32(amount), saleConf.TransCsn, domain.NewTradeNo(partnerId),
				variable.FlowAccountAlias+"转账", "转入"+variable.FlowAccountAlias)
		}
	}

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

// 转账成功提示页面
func (this *accountC) Transfer_success(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)

	src := ctx.Request.URL.Query().Get("src")
	var title, subTitle, btnText string

	switch src {
	case "trans_f2m":
		title = "转账成功"
		subTitle = "转账成功！"
		btnText = "继续转账"
	case "convert_f2p":
		title = "转换成功"
		subTitle = variable.FlowAccountAlias + "转换成功！"
		btnText = "继续转换"
	case "apply_p2b":
		title = "申请成功"
		subTitle = "申请成功，客服将在1-3个工作日完成审核。"
		btnText = "继续提现"
	}

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":     conf,
		"partner":  p,
		"title":    title,
		"subTitle": subTitle,
		"btnText":  btnText,
		"referer":  ctx.Request.Referer(),
	}, "views/ucenter/{device}/account/transfer_success.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Bank_info(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	bank := dps.MemberService.GetBank(m.Id)

	js, _ := json.Marshal(bank)
	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"partner": p,
		"entity":  template.JS(js),
	}, "views/ucenter/{device}/account/bank_info.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}

func (this *accountC) Bank_info_post(ctx *web.Context) {
	m := this.GetMember(ctx)
	r := ctx.Request
	var msg gof.Message
	r.ParseForm()
	e := new(member.BankInfo)
	web.ParseFormToEntity(r.Form, e)
	e.MemberId = m.Id
	err := dps.MemberService.SaveBankInfo(e)

	if err != nil {
		msg.Message = err.Error()
	} else {
		msg.Result = true
	}
	ctx.Response.JsonOutput(msg)
}

func (this *accountC) Integral_exchange(ctx *web.Context) {
	p := this.GetPartner(ctx)
	conf := this.GetSiteConf(p.Id)
	m := this.GetMember(ctx)
	acc, _ := goclient.Member.GetMemberAccount(m.Id, m.DynamicToken)

	this.ExecuteTemplate(ctx, gof.TemplateDataMap{
		"conf":    conf,
		"record":  15,
		"partner": p,
		"member":  m,
		"account": acc,
	}, "views/ucenter/{device}/account/integral_exchange.html",
		"views/ucenter/{device}/inc/header.html",
		"views/ucenter/{device}/inc/menu.html",
		"views/ucenter/{device}/inc/footer.html")
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"mig.ninja/mig"
	"mig.ninja/mig/service"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

// findOSInfo gathers information about the Linux distribution if possible, and
// determines the init type of the system.
func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	defer func() { logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug() }()

	ctx = orig_ctx

	ctx.OSIdent, err = getIdent()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		logChan <- mig.Log{Desc: "warning, no valid linux os identification could be found"}.Info()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

func getIdent() (string, error) {
	methods := []struct {
		name       string
		successLog string
		findFn     func() (string, error)
		validateFn func(string, error) bool
	}{
		{
			name:       "getLSBRelease",
			successLog: "using lsb release for distribution ident",
			findFn:     getLSBRelease,
			validateFn: func(_ string, err error) { return err != nil },
		},
		{
			// Here we check that we read more than '\S'.
			// See https://access.redhat.com/solutions/1138953
			name:       "getIssue",
			successLog: "using /etc/issue for distribution ident",
			findFn:     getIssue,
			validateFn: func(issueName string, err error) { return err != nil && len(issueName) > 3 },
		},
		{
			name:       "getOSRelease",
			successLog: "using /etc/os-release for distribution ident",
			findFn:     getOSRelease,
			validateFn: func(_ string, err error) { return err != nil },
		},
	}

	for _, findMethod := range methods {
		ident, err := findMethod.findFn()
		if !findMethod.validateFn(ident, err) {
			return "", fmt.Errorf("%s failed: %v", findMethod.name, err)
		}
		logChan <- mig.Log{Desc: findMethod.successLog}.Debug()
		return ident, nil
	}

	return "", fmt.Errorf("none of the configured methods for detecting the host's ident worked")
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getOSRelease reads /etc/os-release to retrieve the agent's ident from the
// first line.
func getOSRelease() (string, error) {
	contents, err := ioutil.ReadFile("/etc/os-release")
	if err != nil {
		return "", fmt.Errorf("getOSRelease() -> %v", err)
	}
	index := bytes.IndexByte(contents, byte('\n'))
	if index < 0 {
		return "", fmt.Errorf("getOSRelease() -> OS release name not found")
	}
	return string(contents[0:index]), nil
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}
<commit_msg>We want to return the first ident we find, not fail at the first failure<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"mig.ninja/mig"
	"mig.ninja/mig/service"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

// findOSInfo gathers information about the Linux distribution if possible, and
// determines the init type of the system.
func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	defer func() { logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug() }()

	ctx = orig_ctx

	ctx.OSIdent, err = getIdent()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		logChan <- mig.Log{Desc: "warning, no valid linux os identification could be found"}.Info()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

func getIdent() (string, error) {
	methods := []struct {
		name       string
		successLog string
		findFn     func() (string, error)
		validateFn func(string, error) bool
	}{
		{
			name:       "getLSBRelease",
			successLog: "using lsb release for distribution ident",
			findFn:     getLSBRelease,
			validateFn: func(_ string, err error) { return err != nil },
		},
		{
			// Here we check that we read more than '\S'.
			// See https://access.redhat.com/solutions/1138953
			name:       "getIssue",
			successLog: "using /etc/issue for distribution ident",
			findFn:     getIssue,
			validateFn: func(issueName string, err error) { return err != nil && len(issueName) > 3 },
		},
		{
			name:       "getOSRelease",
			successLog: "using /etc/os-release for distribution ident",
			findFn:     getOSRelease,
			validateFn: func(_ string, err error) { return err != nil },
		},
	}

	for _, findMethod := range methods {
		ident, err := findMethod.findFn()
		if findMethod.validateFn(ident, err) {
			logChan <- mig.Log{Desc: findMethod.successLog}.Debug()
			return ident, nil
		}
		logChan <- mig.Log{Desc: fmt.Errorf("%s failed: %v", findMethod.name, err)}.Debug()
	}

	return "", fmt.Errorf("none of the configured methods for detecting the host's ident worked")
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getOSRelease reads /etc/os-release to retrieve the agent's ident from the
// first line.
func getOSRelease() (string, error) {
	contents, err := ioutil.ReadFile("/etc/os-release")
	if err != nil {
		return "", fmt.Errorf("getOSRelease() -> %v", err)
	}
	index := bytes.IndexByte(contents, byte('\n'))
	if index < 0 {
		return "", fmt.Errorf("getOSRelease() -> OS release name not found")
	}
	return string(contents[0:index]), nil
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}
<|endoftext|>


<commit_before>package mithril

var (
	// SelfClosingTagToken is a list of self closing elements tag
	SelfClosingTagToken = []string{"area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", "!doctype"}
)

// VirtualElement is an object which can convert to real DOM element
type VirtualElement struct {
	Tag      string
	Attrs    *Attributes
	Children interface{}
}

// ID returns the attribute ID of the VirtualElement instance
func (el *VirtualElement) ID() string {
	return el.Attrs.ID
}

// String returns the html string of the element
func (el *VirtualElement) String() string {
	return ""
}
<commit_msg>code improvements to VirtualElement<commit_after>package mithril

var (
	// SelfClosingTagToken is a list of self closing elements tag
	SelfClosingTagToken = []string{"area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", "!doctype"}
)

// VirtualElement is an object which can convert to real DOM element
type VirtualElement struct {
	Tag      string
	Attrs    []Attribute
	Children interface{}
}

// Attr returns or sets the attribute
func (el *VirtualElement) Attr(key string, val ...string) string {
	for _, attr := range el.Attrs {
		if attr.Key() == key {
			if len(val) > 0 {
				attr.Val(val[0])
			}
			return attr.Val()
		}
	}
	if len(val) > 0 {
		el.Attrs = append(el.Attrs, NewStringAttr(key, val[0]))
		return val[0]
	}
	return ""
}

// String returns the html string of the element
func (el *VirtualElement) String() string {
	return ""
}
<|endoftext|>


<commit_before>package ftp

import (
	"fmt"
	"net"
	"bufio"
	"strconv"
	"strings"
)

// FTP struct
type FTPServer struct {
	listener net.Listener // connection instance
	host 	 string
	port 	 int
	config	 *AuthenticationConfig
}

func main() {
	server := &FTPServer{
		host: "0.0.0.0",
		port: 21,
		config: new(AuthenticationConfig),
	}

	server.config.ConfigAuthentication(func(user string, password string) (authenticated bool, dir string) {
		fmt.Println("Logged in " + user + " w/ pass " + password)
		return true, "/root/go/ftp/test"
		})

	err := server.Start()
	if err != nil {
		fmt.Println("Error occurred starting FTP server: " + err.Error())
	}
}

// Starts an FTP server. Must already have a FTPServer instance. This method is blocking.
func (this *FTPServer) Start() (err error) {
	// listen
	listener, err := net.Listen("tcp", this.host + ":" + strconv.Itoa(this.port))
	if err != nil {
		return err
	}

	this.listener = listener

	fmt.Println("FTP Server started on " + this.host + ":" + strconv.Itoa(this.port) + ".")

	// lets go into a for loop for clients
	for {
		conn, err := this.listener.Accept()
		if err != nil {
			fmt.Println("Error occurred accepting FTP client: " + err.Error())
			continue
		}

		client := &FTPClient{
			conn: conn,
			authenticated: false,
			server: this,
		}

		go this.HandleClient(client)
	}

	return nil
}

// This function is used for handling clients, and should be called inside a go routine.
func (this *FTPServer) HandleClient(client *FTPClient) {
	fmt.Println("Now handling client: " + client.conn.RemoteAddr().String())

	// get us a scanner
	client.scanner = bufio.NewScanner(client.conn)
	client.writer = bufio.NewWriter(client.conn)

	// send welcome message, then wait for text
	client.SendMessage(220)

	for client.scanner.Scan() {
		cmd := client.scanner.Text()
		this.HandleRequest(cmd, client)
	}
}

// This function handles an FTP request.
func (this *FTPServer) HandleRequest(req string, client *FTPClient) {
	// get COMMAND, then MESSAGE
	request := strings.SplitAfterN(req, ` `, 2)
	command := strings.Trim(request[0], ` `)

	// did they even send a message?
	if len(request) > 1 {
		message := strings.Trim(request[1], ` `)

		fmt.Println("Command: " + command + ", message: " + message)

		// lets assign the command
		switch command {
		case "USER":
			client.USER(message)
		case "PASS":
			client.PASS(message)
		default:
			client.NOTIMP()
		}

	// there was no message
	} else {
		fmt.Println("Command: " + command)

		// handle
		switch command {
		case "QUIT":
			client.QUIT()
		case "SYST":
			client.SYST()
		case "FEAT":
			client.FEAT()
		default:
			client.NOTIMP()
		}
	}
}<commit_msg>Fixes public access<commit_after>package ftp

import (
	"fmt"
	"net"
	"bufio"
	"strconv"
	"strings"
)

// FTP struct
type FTPServer struct {
	listener net.Listener // connection instance
	Host 	 string
	Port 	 int
	Config	 *AuthenticationConfig
}

func main() {
	server := &FTPServer{
		Host: "0.0.0.0",
		Port: 21,
		Config: new(AuthenticationConfig),
	}

	server.config.ConfigAuthentication(func(user string, password string) (authenticated bool, dir string) {
		fmt.Println("Logged in " + user + " w/ pass " + password)
		return true, "/root/go/ftp/test"
		})

	err := server.Start()
	if err != nil {
		fmt.Println("Error occurred starting FTP server: " + err.Error())
	}
}

// Starts an FTP server. Must already have a FTPServer instance. This method is blocking.
func (this *FTPServer) Start() (err error) {
	// listen
	listener, err := net.Listen("tcp", this.Host + ":" + strconv.Itoa(this.Port))
	if err != nil {
		return err
	}

	this.listener = listener

	fmt.Println("FTP Server started on " + this.Host + ":" + strconv.Itoa(this.Port) + ".")

	// lets go into a for loop for clients
	for {
		conn, err := this.listener.Accept()
		if err != nil {
			fmt.Println("Error occurred accepting FTP client: " + err.Error())
			continue
		}

		client := &FTPClient{
			conn: conn,
			authenticated: false,
			server: this,
		}

		go this.HandleClient(client)
	}

	return nil
}

// This function is used for handling clients, and should be called inside a go routine.
func (this *FTPServer) HandleClient(client *FTPClient) {
	fmt.Println("Now handling client: " + client.conn.RemoteAddr().String())

	// get us a scanner
	client.scanner = bufio.NewScanner(client.conn)
	client.writer = bufio.NewWriter(client.conn)

	// send welcome message, then wait for text
	client.SendMessage(220)

	for client.scanner.Scan() {
		cmd := client.scanner.Text()
		this.HandleRequest(cmd, client)
	}
}

// This function handles an FTP request.
func (this *FTPServer) HandleRequest(req string, client *FTPClient) {
	// get COMMAND, then MESSAGE
	request := strings.SplitAfterN(req, ` `, 2)
	command := strings.Trim(request[0], ` `)

	// did they even send a message?
	if len(request) > 1 {
		message := strings.Trim(request[1], ` `)

		fmt.Println("Command: " + command + ", message: " + message)

		// lets assign the command
		switch command {
		case "USER":
			client.USER(message)
		case "PASS":
			client.PASS(message)
		default:
			client.NOTIMP()
		}

	// there was no message
	} else {
		fmt.Println("Command: " + command)

		// handle
		switch command {
		case "QUIT":
			client.QUIT()
		case "SYST":
			client.SYST()
		case "FEAT":
			client.FEAT()
		default:
			client.NOTIMP()
		}
	}
}<|endoftext|>


<commit_before><commit_msg>change connection mongo<commit_after><|endoftext|>


<commit_before><commit_msg>Closes #35: avoid index out of range when decompressor needs input an… (#36)<commit_after><|endoftext|>


<commit_before><commit_msg>Add `sparta.DashboardDecorator`<commit_after><|endoftext|>


<commit_before>package sia

import (
	"crypto/ecdsa"
	"math/big"
)

const (
	HashSize      = 32
	PublicKeySize = 32
	SignatureSize = 32
	SegmentSize   = 32

	TargetSecondsPerBlock = 300
	TargetWindow          = 5000 // Number of blocks to use when calculating difficulty.

	FutureThreshold = Timestamp(2 * 60 * 60) // Seconds into the future block timestamps are valid.
)

var MaxAdjustmentUp = big.NewRat(10005, 10000)
var MaxAdjustmentDown = big.NewRat(9995, 10000)
var SurpassThreshold = big.NewRat(105, 100)

type (
	Hash      [HashSize]byte
	PublicKey ecdsa.PublicKey

	Timestamp   int64
	BlockHeight uint32
	BlockWeight *big.Rat // inverse of target
	Currency    uint64

	BlockID       Hash
	OutputID      Hash // An output id points to a specific output.
	ContractID    Hash
	TransactionID Hash
	CoinAddress   Hash // An address points to spend conditions.
	Target        Hash
)

type Signature struct {
	R, S *big.Int
}

type Block struct {
	ParentBlock  BlockID
	Timestamp    Timestamp
	Nonce        uint32 // may or may not be needed
	MinerAddress CoinAddress
	MerkleRoot   Hash
	Transactions []Transaction
}

type Transaction struct {
	ArbitraryData []byte
	Inputs        []Input
	MinerFees     []Currency
	Outputs       []Output
	FileContracts []FileContract
	StorageProofs []StorageProof
	Signatures    []TransactionSignature
}

type Input struct {
	OutputID        OutputID // the source of coins for the input
	SpendConditions SpendConditions
}

type Output struct {
	Value     Currency // how many coins are in the output
	SpendHash CoinAddress
}

type SpendConditions struct {
	TimeLock      BlockHeight
	NumSignatures uint8
	PublicKeys    []PublicKey
}

type TransactionSignature struct {
	InputID        OutputID // the OutputID of the Input that this signature is addressing. Using the index has also been considered.
	PublicKeyIndex uint8
	TimeLock       BlockHeight
	// CoveredFields  CoveredFields
	Signature Signature
}

/*
type CoveredFields struct {
	ArbitraryData bool
	MinerFees     []uint8 // each element indicates an index which is signed.
	Inputs        []uint8
	Outputs       []uint8
	Contracts     []uint8
	FileProofs    []uint8
}
*/

// Not enough flexibility in payments?  With the Start and End times, the only
// problem is if the client wishes for the rewards or penalties to scale as
// more are submitted or missed, and if they want things to scale harder in the
// case of consecutive misses.
type FileContract struct {
	ContractFund       Currency
	FileMerkleRoot     Hash
	FileSize           uint64 // probably in bytes, which means the last element in the merkle tree may not be exactly 64 bytes.
	Start, End         BlockHeight
	ChallengeFrequency uint32 // size of window, one window at a time
	Tolerance          uint32 // number of missed proofs before triggering unsuccessful termination
	ValidProofPayout   Currency
	ValidProofAddress  CoinAddress
	MissedProofPayout  Currency
	MissedProofAddress CoinAddress
	SuccessAddress     CoinAddress
	FailureAddress     CoinAddress
}

type StorageProof struct {
	ContractID ContractID
	Segment    [SegmentSize]byte
	HashSet    []*Hash
}

// MarshalSia implements the Marshaler interface for Signatures.
func (s *Signature) MarshalSia() []byte {
	if s.R == nil || s.S == nil {
		return []byte{0, 0}
	}
	// pretend Signature is a tuple of []bytes
	// this lets us use Marshal instead of doing manual length-prefixing
	return Marshal(struct{ R, S []byte }{s.R.Bytes(), s.S.Bytes()})
}

// MarshalSia implements the Unmarshaler interface for Signatures.
func (s *Signature) UnmarshalSia(b []byte) int {
	// inverse of the struct trick used in Signature.MarshalSia
	str := struct{ R, S []byte }{}
	if Unmarshal(b, &str) != nil {
		return 0
	}
	s.R = new(big.Int).SetBytes(str.R)
	s.S = new(big.Int).SetBytes(str.S)
	return len(str.R) + len(str.S) + 2
}

// MarshalSia implements the Marshaler interface for PublicKeys.
func (pk *PublicKey) MarshalSia() []byte {
	if pk.X == nil || pk.Y == nil {
		return []byte{0, 0}
	}
	// see Signature.MarshalSia
	return Marshal(struct{ X, Y []byte }{pk.X.Bytes(), pk.Y.Bytes()})
}

// MarshalSia implements the Unmarshaler interface for PublicKeys.
func (pk *PublicKey) UnmarshalSia(b []byte) int {
	// see Signature.UnmarshalSia
	str := struct{ X, Y []byte }{}
	if Unmarshal(b, &str) != nil {
		return 0
	}
	pk.X = new(big.Int).SetBytes(str.X)
	pk.Y = new(big.Int).SetBytes(str.Y)
	return len(str.X) + len(str.Y) + 2
}

// MerkleRoot calculates the Merkle root hash of a SpendConditions object,
// using the timelock, number of signatures, and the signatures themselves as leaves.
func (sc *SpendConditions) MerkleRoot() Hash {
	tlHash := HashBytes(Marshal(sc.TimeLock))
	nsHash := HashBytes(Marshal(sc.NumSignatures))
	pkHashes := make([]Hash, len(sc.PublicKeys))
	for i := range sc.PublicKeys {
		pkHashes[i] = HashBytes(Marshal(sc.PublicKeys[i]))
	}
	leaves := append([]Hash{tlHash, nsHash}, pkHashes...)
	return MerkleRoot(leaves)
}

func (b *Block) ID() BlockID {
	return BlockID(HashBytes(Marshal(b))) // this may be wrong, since it encodes every field
}

func (t *Transaction) Hash() Hash {
	// version, hash of arb data, miner fee, each input, each output, each file contract, each sp, each sig
	// allows you to selectively reveal pieces of a transaction? But what good is that?

	return HashBytes(Marshal(t)) // this may be wrong, since it encodes every field
}
<commit_msg>implement Block.ID and Txn.SigHash<commit_after>package sia

import (
	"crypto/ecdsa"
	"math/big"
)

const (
	HashSize      = 32
	PublicKeySize = 32
	SignatureSize = 32
	SegmentSize   = 32

	TargetSecondsPerBlock = 300
	TargetWindow          = 5000 // Number of blocks to use when calculating difficulty.

	FutureThreshold = Timestamp(2 * 60 * 60) // Seconds into the future block timestamps are valid.
)

var MaxAdjustmentUp = big.NewRat(10005, 10000)
var MaxAdjustmentDown = big.NewRat(9995, 10000)
var SurpassThreshold = big.NewRat(105, 100)

type (
	Hash      [HashSize]byte
	PublicKey ecdsa.PublicKey

	Timestamp   int64
	BlockHeight uint32
	BlockWeight *big.Rat // inverse of target
	Currency    uint64

	BlockID       Hash
	OutputID      Hash // An output id points to a specific output.
	ContractID    Hash
	TransactionID Hash
	CoinAddress   Hash // An address points to spend conditions.
	Target        Hash
)

type Signature struct {
	R, S *big.Int
}

type Block struct {
	ParentBlock  BlockID
	Timestamp    Timestamp
	Nonce        uint32 // may or may not be needed
	MinerAddress CoinAddress
	MerkleRoot   Hash
	Transactions []Transaction
}

type Transaction struct {
	ArbitraryData []byte
	Inputs        []Input
	MinerFees     []Currency
	Outputs       []Output
	FileContracts []FileContract
	StorageProofs []StorageProof
	Signatures    []TransactionSignature
}

type Input struct {
	OutputID        OutputID // the source of coins for the input
	SpendConditions SpendConditions
}

type Output struct {
	Value     Currency // how many coins are in the output
	SpendHash CoinAddress
}

type SpendConditions struct {
	TimeLock      BlockHeight
	NumSignatures uint8
	PublicKeys    []PublicKey
}

type TransactionSignature struct {
	InputID        OutputID // the OutputID of the Input that this signature is addressing. Using the index has also been considered.
	PublicKeyIndex uint8
	TimeLock       BlockHeight
	// CoveredFields  CoveredFields
	Signature Signature
}

/*
type CoveredFields struct {
	ArbitraryData bool
	MinerFees     []uint8 // each element indicates an index which is signed.
	Inputs        []uint8
	Outputs       []uint8
	Contracts     []uint8
	FileProofs    []uint8
}
*/

// Not enough flexibility in payments?  With the Start and End times, the only
// problem is if the client wishes for the rewards or penalties to scale as
// more are submitted or missed, and if they want things to scale harder in the
// case of consecutive misses.
type FileContract struct {
	ContractFund       Currency
	FileMerkleRoot     Hash
	FileSize           uint64 // probably in bytes, which means the last element in the merkle tree may not be exactly 64 bytes.
	Start, End         BlockHeight
	ChallengeFrequency uint32 // size of window, one window at a time
	Tolerance          uint32 // number of missed proofs before triggering unsuccessful termination
	ValidProofPayout   Currency
	ValidProofAddress  CoinAddress
	MissedProofPayout  Currency
	MissedProofAddress CoinAddress
	SuccessAddress     CoinAddress
	FailureAddress     CoinAddress
}

type StorageProof struct {
	ContractID ContractID
	Segment    [SegmentSize]byte
	HashSet    []*Hash
}

// MarshalSia implements the Marshaler interface for Signatures.
func (s *Signature) MarshalSia() []byte {
	if s.R == nil || s.S == nil {
		return []byte{0, 0}
	}
	// pretend Signature is a tuple of []bytes
	// this lets us use Marshal instead of doing manual length-prefixing
	return Marshal(struct{ R, S []byte }{s.R.Bytes(), s.S.Bytes()})
}

// MarshalSia implements the Unmarshaler interface for Signatures.
func (s *Signature) UnmarshalSia(b []byte) int {
	// inverse of the struct trick used in Signature.MarshalSia
	str := struct{ R, S []byte }{}
	if Unmarshal(b, &str) != nil {
		return 0
	}
	s.R = new(big.Int).SetBytes(str.R)
	s.S = new(big.Int).SetBytes(str.S)
	return len(str.R) + len(str.S) + 2
}

// MarshalSia implements the Marshaler interface for PublicKeys.
func (pk *PublicKey) MarshalSia() []byte {
	if pk.X == nil || pk.Y == nil {
		return []byte{0, 0}
	}
	// see Signature.MarshalSia
	return Marshal(struct{ X, Y []byte }{pk.X.Bytes(), pk.Y.Bytes()})
}

// MarshalSia implements the Unmarshaler interface for PublicKeys.
func (pk *PublicKey) UnmarshalSia(b []byte) int {
	// see Signature.UnmarshalSia
	str := struct{ X, Y []byte }{}
	if Unmarshal(b, &str) != nil {
		return 0
	}
	pk.X = new(big.Int).SetBytes(str.X)
	pk.Y = new(big.Int).SetBytes(str.Y)
	return len(str.X) + len(str.Y) + 2
}

// ID returns the Block's unique identifier, generated from the hash of its internal data.
// Transactions are not included in the hash.
func (b *Block) ID() BlockID {
	return BlockID(HashBytes(MarshalAll(
		b.ParentBlock,
		b.Timestamp,
		b.Nonce,
		b.MinerAddress,
		b.MerkleRoot,
	)))
}

// MerkleRoot calculates the Merkle root hash of a SpendConditions object,
// using the timelock, number of signatures, and the signatures themselves as leaves.
func (sc *SpendConditions) MerkleRoot() Hash {
	tlHash := HashBytes(Marshal(sc.TimeLock))
	nsHash := HashBytes(Marshal(sc.NumSignatures))
	pkHashes := make([]Hash, len(sc.PublicKeys))
	for i := range sc.PublicKeys {
		pkHashes[i] = HashBytes(Marshal(sc.PublicKeys[i]))
	}
	leaves := append([]Hash{tlHash, nsHash}, pkHashes...)
	return MerkleRoot(leaves)
}

// SigHash returns the hash of a transaction for a specific index.
// The index determines which TransactionSignature is included in the hash.
func (t *Transaction) SigHash(i int) Hash {
	return HashBytes(MarshalAll(
		t.ArbitraryData,
		t.Inputs,
		t.MinerFees,
		t.Outputs,
		t.FileContracts,
		t.StorageProofs,
		t.Signatures[i].InputID,
		t.Signatures[i].PublicKeyIndex,
		t.Signatures[i].TimeLock,
	))
}
<|endoftext|>


<commit_before>package irc

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

type ClientConfiguration struct {
	Name                 string `json:"name"`
	Host                 string `json:"host"`
	Port                 int    `json:"port"`
	IsTLS                bool   `json:"is_tls"`
	SkipCertificateCheck bool   `json:"skip_certificate_check,omitempty"`

	Nick           string   `json:"nick"`
	RealName       string   `json:"real_name"`
	ServerPass     string   `json:"server_pass,omitempty"`
	OnConnect      []string `json:"on_connect"`
	RejoinExisting bool     `json:"rejoin_existing"`
}

type Client struct {
	ClientConfiguration

	conn *irc.Conn
	mux  sync.Mutex

	buffers map[string]buffer

	directory string
}

type buffer struct {
	ch     chan *irc.Message
	client *Client
	path   string

	name  string
	topic string
	users map[string]string
}

const serverBufferName = "$server"

func NewClient(baseDir string, cfg ClientConfiguration) *Client {
	client := &Client{
		ClientConfiguration: cfg,

		directory: filepath.Join(baseDir, cfg.Name),
		buffers:   make(map[string]buffer),
	}

	return client
}

func (c *Client) Initialize() error {
	c.serverBuffer().writeInfoMessage("connecting ...")

	server := fmt.Sprintf("%s:%d", c.Host, c.Port)

	var err error
	if c.IsTLS {
		t := &tls.Config{InsecureSkipVerify: c.SkipCertificateCheck}
		c.conn, err = irc.DialTLS(server, t)
	} else {
		c.conn, err = irc.Dial(server)
	}

	if err != nil {
		return err
	}

	if c.ServerPass != "" {
		c.send("PASS", c.ServerPass)
	}

	r := c.RealName
	if r == "" {
		r = c.Nick
	}

	c.send("NICK", c.Nick)
	c.send("USER", c.Nick, "*", "*", c.RealName)

	return nil
}

func (c *Client) send(cmd string, params ...string) {
	msg := &irc.Message{
		Command: cmd,
		Params:  params,
	}

	c.conn.Encode(msg)

	fmt.Printf("[%s] --> %+v\n", c.Name, msg)
}

func (c *Client) sendRaw(msg string) {
	c.conn.Write([]byte(msg))
	fmt.Printf("[%s] --> %+v\n", c.Name, msg)
}

func (c *Client) listExistingChannels() []string {
	files, err := ioutil.ReadDir(c.directory)
	if err != nil {
		log.Fatal(err)
	}

	channels := []string{}
	for _, file := range files {
		name := file.Name()
		if isChannel(name) {
			channels = append(channels, name)
		}
	}

	return channels
}

func (b *buffer) writeInfoMessage(msg string) {
	b.ch <- &irc.Message{
		Prefix:  &irc.Prefix{Name: "uex"},
		Command: "*",
		Params:  []string{msg},
	}

}

func (c *Client) handleMessage(msg *irc.Message) {
	buf := c.getBuffer(serverBufferName)

	switch msg.Command {
	case irc.RPL_WELCOME:
		for _, msg := range c.OnConnect {
			c.sendRaw(msg)
		}

		if c.RejoinExisting {
			for _, ch := range c.listExistingChannels() {
				c.send(irc.JOIN, ch)
			}
		}

	case irc.PING:
		c.send(irc.PONG, msg.Params...)

	case irc.PONG:
		if len(msg.Params) != 2 {
			break
		}

		s := strings.SplitN(msg.Params[1], " ", 2)
		if len(s) != 2 {
			break
		}

		if ts, err := strconv.ParseInt(s[1], 10, 64); err == nil {
			delta := time.Duration(time.Now().UnixNano()-ts) / time.Millisecond
			text := fmt.Sprintf("PONG from %s: %d ms", msg.Params[0], delta)

			buf.writeInfoMessage(text)
		}

	case irc.NICK:
		from := msg.Prefix.Name
		to := msg.Params[0]

		if from == c.Nick {
			c.Nick = to

			text := fmt.Sprintf("changed nick from %s to %s", from, to)
			buf.writeInfoMessage(text)
		} else {
			// TODO: broadcast renames to all bufs having that user?
			// requires more tracking
			buf = nil
		}

	case irc.JOIN:
		buf = c.getBuffer(msg.Params[0])

	case irc.PRIVMSG, irc.NOTICE:
		target := msg.Params[0]

		// Group all messages sent by the server together,
		// regardless of server name.
		//
		// For direct messages, we want to look at the sender.
		if msg.Prefix.IsServer() {
			target = serverBufferName
		} else if !isChannel(target) {
			target = msg.Prefix.Name
		}

		buf = c.getBuffer(target)

	case irc.RPL_TOPIC:
		target := msg.Params[1]
		topic := msg.Params[2]

		c.getBuffer(target).topic = topic

	case irc.ERR_NICKNAMEINUSE:
		c.Nick = c.Nick + "`"
		fmt.Printf("Nick in use, trying '%s'\n", c.Nick)
		c.send("NICK", c.Nick)
	}

	if buf != nil {
		buf.ch <- msg
	}
}

func (c *Client) serverBuffer() *buffer {
	return c.getBuffer(serverBufferName)
}

func (c *Client) getBuffer(name string) *buffer {
	c.mux.Lock()
	defer c.mux.Unlock()

	// Sent early on, at least by freenode.
	if name == "*" {
		name = serverBufferName
	}

	if buf, exists := c.buffers[name]; exists {
		return &buf
	}

	path := c.directory

	// We want to write __in, __out top level for the server, and
	// as a child for every other buffer.
	if name != serverBufferName {
		path = filepath.Join(path, name)
	}

	if err := os.MkdirAll(path, os.ModePerm); err != nil {
		log.Fatal(err)
	}

	c.buffers[name] = buffer{
		ch:     make(chan *irc.Message),
		client: c,
		path:   path,

		name:  name,
		topic: "",
		users: make(map[string]string),
	}

	b := c.buffers[name]

	go b.inputHandler()
	go b.outputHandler()

	return &b
}

func (b *buffer) outputHandler() {
	name := filepath.Join(b.path, "__out")
	mode := os.O_APPEND | os.O_RDWR | os.O_CREATE
	file, err := os.OpenFile(name, mode, 0644)
	if err != nil {
		log.Fatalf("failed to create output file: %+v\n", err)
	}

	defer file.Close()

	// TODO: better serialization?? colors?? etc.
	for msg := range b.ch {
		text := formatMessage(msg)
		if text == "" {
			continue
		}

		if _, err := file.WriteString(text + "\n"); err != nil {
			log.Fatal(err)
		}
		if err := file.Sync(); err != nil {
			log.Fatal(err)
		}
	}
}

func (b *buffer) inputHandler() {
	name := filepath.Join(b.path, "__in")
	err := syscall.Mkfifo(name, 0777)

	// Doesn't matter if the FIFO already exists from a previous run.
	if err != nil && err != syscall.EEXIST {
		log.Fatal(err)
	}

	for {
		buf, err := ioutil.ReadFile(name)
		if err != nil {
			log.Fatal(err)
		}

		if len(buf) == 0 {
			time.Sleep(100 * time.Millisecond)
			continue
		}

		lines := strings.Split(string(buf), "\n")
		for _, line := range lines {
			line = strings.TrimSpace(line)
			if line == "" {
				continue
			}

			b.client.handleInputLine(b.name, line)
		}
	}
}

func isChannel(target string) bool {
	if target == "" {
		return false
	}

	return target[0] == '#' || target[0] == '&'
}

func splitInputCommand(bufName, line string) (string, string) {
	// Without a prefix, it's just a regular PRIVMSG
	if !strings.HasPrefix(line, "/") {
		return "/msg", bufName + " " + line
	}
	// Double slash at start means privmsg with leading slash
	if strings.HasPrefix(line, "//") {
		return "/msg", bufName + " " + line[1:]
	}

	s := strings.SplitN(line, " ", 2)
	cmd := strings.ToLower(s[0])

	if len(s) == 1 {
		return cmd, ""
	}

	return cmd, s[1]
}

func (c *Client) handleInputLine(bufName, line string) {
	fmt.Printf("[%s/%s] >> %s\n", c.Name, bufName, line)

	cmd, rest := splitInputCommand(bufName, line)

	switch cmd {
	case "/m", "/msg":
		s := strings.SplitN(rest, " ", 2)
		if len(s) != 2 {
			c.serverBuffer().writeInfoMessage("expected: /msg TARGET MESSAGE")
			return
		} else if s[0] == serverBufferName {
			c.serverBuffer().writeInfoMessage("can't PRIVMSG a server.")
			return
		}

		buf := c.getBuffer(s[0])

		// TODO: pull this out into simple `buf.AddMessage` or so
		buf.ch <- &irc.Message{
			Prefix:  &irc.Prefix{Name: c.Nick},
			Command: irc.PRIVMSG,
			Params:  []string{s[1]},
		}

		c.send("PRIVMSG", s[0], s[1])

	case "/j", "/join":
		if !isChannel(rest) {
			c.getBuffer(bufName).writeInfoMessage("expected: /join TARGET")
			return
		}
		c.send("JOIN", rest)

	case "/l", "/list":
		buf := c.getBuffer(bufName)

		buf.writeInfoMessage("~~ buffers ~~")
		for k, _ := range c.buffers {
			buf.writeInfoMessage(" " + k)
		}

	case "/ping":
		ts := time.Now().UnixNano()
		c.send("PING", fmt.Sprintf("%s %d", bufName, ts))

	case "/quote":
		params := strings.Split(rest, " ")
		if len(params) == 1 {
			c.send(params[0])
		} else {
			c.send(params[0], params[1:]...)
		}

	case "/r", "/reconnect":
		c.serverBuffer().writeInfoMessage("... disconnecting")
		if err := c.conn.Close(); err != nil {
			fmt.Printf("failed to close: %+v\n", err)
		}

	default:
		text := fmt.Sprintf("Unknown command: %s %s", cmd, rest)
		c.getBuffer(bufName).writeInfoMessage(text)
	}
}

func (c *Client) RunLoop() error {
	for {
		message, err := c.conn.Decode()
		if err != nil {
			return err
		}

		fmt.Printf("[%s] <-- %+v\n", c.Name, message)
		c.handleMessage(message)
	}
}
<commit_msg>Set TCP keepalive on connection<commit_after>package irc

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

type ClientConfiguration struct {
	Name                 string `json:"name"`
	Host                 string `json:"host"`
	Port                 int    `json:"port"`
	IsTLS                bool   `json:"is_tls"`
	SkipCertificateCheck bool   `json:"skip_certificate_check,omitempty"`

	Nick           string   `json:"nick"`
	RealName       string   `json:"real_name"`
	ServerPass     string   `json:"server_pass,omitempty"`
	OnConnect      []string `json:"on_connect"`
	RejoinExisting bool     `json:"rejoin_existing"`
}

type Client struct {
	ClientConfiguration

	conn *irc.Conn
	mux  sync.Mutex

	buffers map[string]buffer

	directory string
}

type buffer struct {
	ch     chan *irc.Message
	client *Client
	path   string

	name  string
	topic string
	users map[string]string
}

const serverBufferName = "$server"

func NewClient(baseDir string, cfg ClientConfiguration) *Client {
	client := &Client{
		ClientConfiguration: cfg,

		directory: filepath.Join(baseDir, cfg.Name),
		buffers:   make(map[string]buffer),
	}

	return client
}

func (c *Client) connect() (*net.Conn, error) {
	c.serverBuffer().writeInfoMessage("connecting ...")

	server := fmt.Sprintf("%s:%d", c.Host, c.Port)

	conn, err := net.Dial("tcp", server)
	if err != nil {
		return nil, err
	}

	tcpc := conn.(*net.TCPConn)
	if err = tcpc.SetKeepAlive(true); err != nil {
		return nil, err
	}
	if err = tcpc.SetKeepAlivePeriod(5 * time.Minute); err != nil {
		return nil, err
	}

	if c.IsTLS {
		conn = tls.Client(conn, &tls.Config{
			ServerName:         c.Host,
			InsecureSkipVerify: c.SkipCertificateCheck,
		})
	}

	return &conn, nil
}

func (c *Client) Initialize() error {
	conn, err := c.connect()
	if err != nil {
		return err
	}

	c.conn = irc.NewConn(*conn)

	if c.ServerPass != "" {
		c.send("PASS", c.ServerPass)
	}

	r := c.RealName
	if r == "" {
		r = c.Nick
	}

	c.send("NICK", c.Nick)
	c.send("USER", c.Nick, "*", "*", c.RealName)

	return nil
}

func (c *Client) send(cmd string, params ...string) {
	msg := &irc.Message{
		Command: cmd,
		Params:  params,
	}

	c.conn.Encode(msg)

	fmt.Printf("[%s] --> %+v\n", c.Name, msg)
}

func (c *Client) sendRaw(msg string) {
	c.conn.Write([]byte(msg))
	fmt.Printf("[%s] --> %+v\n", c.Name, msg)
}

func (c *Client) listExistingChannels() []string {
	files, err := ioutil.ReadDir(c.directory)
	if err != nil {
		log.Fatal(err)
	}

	channels := []string{}
	for _, file := range files {
		name := file.Name()
		if isChannel(name) {
			channels = append(channels, name)
		}
	}

	return channels
}

func (b *buffer) writeInfoMessage(msg string) {
	b.ch <- &irc.Message{
		Prefix:  &irc.Prefix{Name: "uex"},
		Command: "*",
		Params:  []string{msg},
	}

}

func (c *Client) handleMessage(msg *irc.Message) {
	buf := c.getBuffer(serverBufferName)

	switch msg.Command {
	case irc.RPL_WELCOME:
		for _, msg := range c.OnConnect {
			c.sendRaw(msg)
		}

		if c.RejoinExisting {
			for _, ch := range c.listExistingChannels() {
				c.send(irc.JOIN, ch)
			}
		}

	case irc.PING:
		c.send(irc.PONG, msg.Params...)

	case irc.PONG:
		if len(msg.Params) != 2 {
			break
		}

		s := strings.SplitN(msg.Params[1], " ", 2)
		if len(s) != 2 {
			break
		}

		if ts, err := strconv.ParseInt(s[1], 10, 64); err == nil {
			delta := time.Duration(time.Now().UnixNano()-ts) / time.Millisecond
			text := fmt.Sprintf("PONG from %s: %d ms", msg.Params[0], delta)

			buf.writeInfoMessage(text)
		}

	case irc.NICK:
		from := msg.Prefix.Name
		to := msg.Params[0]

		if from == c.Nick {
			c.Nick = to

			text := fmt.Sprintf("changed nick from %s to %s", from, to)
			buf.writeInfoMessage(text)
		} else {
			// TODO: broadcast renames to all bufs having that user?
			// requires more tracking
			buf = nil
		}

	case irc.JOIN:
		buf = c.getBuffer(msg.Params[0])

	case irc.PRIVMSG, irc.NOTICE:
		target := msg.Params[0]

		// Group all messages sent by the server together,
		// regardless of server name.
		//
		// For direct messages, we want to look at the sender.
		if msg.Prefix.IsServer() {
			target = serverBufferName
		} else if !isChannel(target) {
			target = msg.Prefix.Name
		}

		buf = c.getBuffer(target)

	case irc.RPL_TOPIC:
		target := msg.Params[1]
		topic := msg.Params[2]

		c.getBuffer(target).topic = topic

	case irc.ERR_NICKNAMEINUSE:
		c.Nick = c.Nick + "`"
		fmt.Printf("Nick in use, trying '%s'\n", c.Nick)
		c.send("NICK", c.Nick)
	}

	if buf != nil {
		buf.ch <- msg
	}
}

func (c *Client) serverBuffer() *buffer {
	return c.getBuffer(serverBufferName)
}

func (c *Client) getBuffer(name string) *buffer {
	c.mux.Lock()
	defer c.mux.Unlock()

	// Sent early on, at least by freenode.
	if name == "*" {
		name = serverBufferName
	}

	if buf, exists := c.buffers[name]; exists {
		return &buf
	}

	path := c.directory

	// We want to write __in, __out top level for the server, and
	// as a child for every other buffer.
	if name != serverBufferName {
		path = filepath.Join(path, name)
	}

	if err := os.MkdirAll(path, os.ModePerm); err != nil {
		log.Fatal(err)
	}

	c.buffers[name] = buffer{
		ch:     make(chan *irc.Message),
		client: c,
		path:   path,

		name:  name,
		topic: "",
		users: make(map[string]string),
	}

	b := c.buffers[name]

	go b.inputHandler()
	go b.outputHandler()

	return &b
}

func (b *buffer) outputHandler() {
	name := filepath.Join(b.path, "__out")
	mode := os.O_APPEND | os.O_RDWR | os.O_CREATE
	file, err := os.OpenFile(name, mode, 0644)
	if err != nil {
		log.Fatalf("failed to create output file: %+v\n", err)
	}

	defer file.Close()

	// TODO: better serialization?? colors?? etc.
	for msg := range b.ch {
		text := formatMessage(msg)
		if text == "" {
			continue
		}

		if _, err := file.WriteString(text + "\n"); err != nil {
			log.Fatal(err)
		}
		if err := file.Sync(); err != nil {
			log.Fatal(err)
		}
	}
}

func (b *buffer) inputHandler() {
	name := filepath.Join(b.path, "__in")
	err := syscall.Mkfifo(name, 0777)

	// Doesn't matter if the FIFO already exists from a previous run.
	if err != nil && err != syscall.EEXIST {
		log.Fatal(err)
	}

	for {
		buf, err := ioutil.ReadFile(name)
		if err != nil {
			log.Fatal(err)
		}

		if len(buf) == 0 {
			time.Sleep(100 * time.Millisecond)
			continue
		}

		lines := strings.Split(string(buf), "\n")
		for _, line := range lines {
			line = strings.TrimSpace(line)
			if line == "" {
				continue
			}

			b.client.handleInputLine(b.name, line)
		}
	}
}

func isChannel(target string) bool {
	if target == "" {
		return false
	}

	return target[0] == '#' || target[0] == '&'
}

func splitInputCommand(bufName, line string) (string, string) {
	// Without a prefix, it's just a regular PRIVMSG
	if !strings.HasPrefix(line, "/") {
		return "/msg", bufName + " " + line
	}
	// Double slash at start means privmsg with leading slash
	if strings.HasPrefix(line, "//") {
		return "/msg", bufName + " " + line[1:]
	}

	s := strings.SplitN(line, " ", 2)
	cmd := strings.ToLower(s[0])

	if len(s) == 1 {
		return cmd, ""
	}

	return cmd, s[1]
}

func (c *Client) handleInputLine(bufName, line string) {
	fmt.Printf("[%s/%s] >> %s\n", c.Name, bufName, line)

	cmd, rest := splitInputCommand(bufName, line)

	switch cmd {
	case "/m", "/msg":
		s := strings.SplitN(rest, " ", 2)
		if len(s) != 2 {
			c.serverBuffer().writeInfoMessage("expected: /msg TARGET MESSAGE")
			return
		} else if s[0] == serverBufferName {
			c.serverBuffer().writeInfoMessage("can't PRIVMSG a server.")
			return
		}

		buf := c.getBuffer(s[0])

		// TODO: pull this out into simple `buf.AddMessage` or so
		buf.ch <- &irc.Message{
			Prefix:  &irc.Prefix{Name: c.Nick},
			Command: irc.PRIVMSG,
			Params:  []string{s[1]},
		}

		c.send("PRIVMSG", s[0], s[1])

	case "/j", "/join":
		if !isChannel(rest) {
			c.getBuffer(bufName).writeInfoMessage("expected: /join TARGET")
			return
		}
		c.send("JOIN", rest)

	case "/l", "/list":
		buf := c.getBuffer(bufName)

		buf.writeInfoMessage("~~ buffers ~~")
		for k, _ := range c.buffers {
			buf.writeInfoMessage(" " + k)
		}

	case "/ping":
		ts := time.Now().UnixNano()
		c.send("PING", fmt.Sprintf("%s %d", bufName, ts))

	case "/quote":
		params := strings.Split(rest, " ")
		if len(params) == 1 {
			c.send(params[0])
		} else {
			c.send(params[0], params[1:]...)
		}

	case "/r", "/reconnect":
		c.serverBuffer().writeInfoMessage("... disconnecting")
		if err := c.conn.Close(); err != nil {
			fmt.Printf("failed to close: %+v\n", err)
		}

	default:
		text := fmt.Sprintf("Unknown command: %s %s", cmd, rest)
		c.getBuffer(bufName).writeInfoMessage(text)
	}
}

func (c *Client) RunLoop() error {
	for {
		message, err := c.conn.Decode()
		if err != nil {
			return err
		}

		fmt.Printf("[%s] <-- %+v\n", c.Name, message)
		c.handleMessage(message)
	}
}
<|endoftext|>


<commit_before>package poet

import (
	"bytes"
	"fmt"
)

// FileSpec represents a .go source file
>>>>>>> c66c5eb96c7d49ed805a884f436dfcbe53940869
type FileSpec struct {
	Package                string      // Package that the file belongs to
	InitializationPackages []Import    // InitializationPackages include any imports that need to be included for their side effects
	Init                   *FuncSpec   // Init is a single function to be outputted before all CodeBlocks
	CodeBlocks             []CodeBlock // CodeBlocks are appeneded and when outputted separated by a newline
}

// NewFileSpec constructs a new FileSpec with the given package name
func NewFileSpec(pkg string) *FileSpec {
	return &FileSpec{
		Package:                pkg,
		InitializationPackages: []Import{},
		CodeBlocks:             []CodeBlock{},
	}
}

// String produces the final go file string
func (f *FileSpec) String() string {
	var buffer bytes.Buffer
	didStartImportBlock := false

	buffer.WriteString("package " + f.Package + "\n\n")
	seen := map[string]struct{}{}

	var packages []Import
	for _, blk := range f.CodeBlocks {
		packages = append(packages, blk.GetImports()...)
	}

	for _, imp := range f.InitializationPackages {
		if _, found := seen[imp.GetPackage()]; !found && imp.GetPackage() != "" {
			if !didStartImportBlock {
				buffer.WriteString("import (\n")
				didStartImportBlock = true
			}

			buffer.WriteString("\t_ ")
			buffer.WriteString("\"" + imp.GetPackage() + "\"\n")
			seen[imp.GetPackage()] = struct{}{}
		}
	}

	for _, imp := range packages {
		if _, found := seen[imp.GetPackage()]; !found && imp.GetPackage() != "" {
			if !didStartImportBlock {
				buffer.WriteString("import (\n")
				didStartImportBlock = true
			}

			buffer.WriteString("\t")
			if imp.GetAlias() != "" {
				buffer.WriteString(imp.GetAlias())
				buffer.WriteString(" ")
			}
			buffer.WriteString("\"" + imp.GetPackage() + "\"\n")
			seen[imp.GetPackage()] = struct{}{}
		}
	}

	if didStartImportBlock {
		buffer.WriteString(")\n\n")
	}

	// create a new array with codeBlocks
	var codeBlocks []CodeBlock
	if f.Init != nil {
		if f.Init.Name != "init" {
			panic(fmt.Sprintf("the init function must be named 'init' (got '%s')", f.Init.Name))
		}

		codeBlocks = append([]CodeBlock{f.Init}, f.CodeBlocks...)
	} else {
		codeBlocks = append([]CodeBlock(nil), f.CodeBlocks...)
	}

	for _, codeBlk := range codeBlocks {
		buffer.WriteString(codeBlk.String())
		buffer.WriteString("\n")
	}

	return buffer.String()
}

// InitializationPackage appends an initialization package for its side effects
func (f *FileSpec) InitializationPackage(imp Import) *FileSpec {
	f.InitializationPackages = append(f.InitializationPackages, imp)
	return f
}

// CodeBlock adds a code block to the file
func (f *FileSpec) CodeBlock(blk CodeBlock) *FileSpec {
	f.CodeBlocks = append(f.CodeBlocks, blk)
	return f
}

// InitFunction assign an init function
func (f *FileSpec) InitFunction(blk *FuncSpec) *FileSpec {
	f.Init = blk
	return f
}

// GlobalVariable adds a global variable to the file with the given name, type reference, format string
// for the value of the variable, and arguments for the format string.
func (f *FileSpec) GlobalVariable(name string, typ TypeReference, format string, args ...interface{}) *FileSpec {
	v := &Variable{
		Identifier: Identifier{
			Name: name,
			Type: typ,
		},
		Constant: false,
		Format:   format,
		Args:     args,
	}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return f
}

// GlobalConstant adds a global constant to the file with the given name, type reference, format string
// for the value of the constant, and arguments for the format string.
func (f *FileSpec) GlobalConstant(name string, typ TypeReference, format string, args ...interface{}) *FileSpec {
	v := &Variable{
		Identifier: Identifier{
			Name: name,
			Type: typ,
		},
		Constant: true,
		Format:   format,
		Args:     args,
	}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return f
}

// VariableGrouping adds a variable grouping to the file, which can have variables appended to it
// that will be formatted in groups of variables and constants.
func (f *FileSpec) VariableGrouping() *VariableGrouping {
	v := &VariableGrouping{}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return v
}
<commit_msg>unbreak build<commit_after>package poet

import (
	"bytes"
	"fmt"
)

// FileSpec represents a .go source file
type FileSpec struct {
	Package                string      // Package that the file belongs to
	InitializationPackages []Import    // InitializationPackages include any imports that need to be included for their side effects
	Init                   *FuncSpec   // Init is a single function to be outputted before all CodeBlocks
	CodeBlocks             []CodeBlock // CodeBlocks are appeneded and when outputted separated by a newline
}

// NewFileSpec constructs a new FileSpec with the given package name
func NewFileSpec(pkg string) *FileSpec {
	return &FileSpec{
		Package:                pkg,
		InitializationPackages: []Import{},
		CodeBlocks:             []CodeBlock{},
	}
}

// String produces the final go file string
func (f *FileSpec) String() string {
	var buffer bytes.Buffer
	didStartImportBlock := false

	buffer.WriteString("package " + f.Package + "\n\n")
	seen := map[string]struct{}{}

	var packages []Import
	for _, blk := range f.CodeBlocks {
		packages = append(packages, blk.GetImports()...)
	}

	for _, imp := range f.InitializationPackages {
		if _, found := seen[imp.GetPackage()]; !found && imp.GetPackage() != "" {
			if !didStartImportBlock {
				buffer.WriteString("import (\n")
				didStartImportBlock = true
			}

			buffer.WriteString("\t_ ")
			buffer.WriteString("\"" + imp.GetPackage() + "\"\n")
			seen[imp.GetPackage()] = struct{}{}
		}
	}

	for _, imp := range packages {
		if _, found := seen[imp.GetPackage()]; !found && imp.GetPackage() != "" {
			if !didStartImportBlock {
				buffer.WriteString("import (\n")
				didStartImportBlock = true
			}

			buffer.WriteString("\t")
			if imp.GetAlias() != "" {
				buffer.WriteString(imp.GetAlias())
				buffer.WriteString(" ")
			}
			buffer.WriteString("\"" + imp.GetPackage() + "\"\n")
			seen[imp.GetPackage()] = struct{}{}
		}
	}

	if didStartImportBlock {
		buffer.WriteString(")\n\n")
	}

	// create a new array with codeBlocks
	var codeBlocks []CodeBlock
	if f.Init != nil {
		if f.Init.Name != "init" {
			panic(fmt.Sprintf("the init function must be named 'init' (got '%s')", f.Init.Name))
		}

		codeBlocks = append([]CodeBlock{f.Init}, f.CodeBlocks...)
	} else {
		codeBlocks = append([]CodeBlock(nil), f.CodeBlocks...)
	}

	for _, codeBlk := range codeBlocks {
		buffer.WriteString(codeBlk.String())
		buffer.WriteString("\n")
	}

	return buffer.String()
}

// InitializationPackage appends an initialization package for its side effects
func (f *FileSpec) InitializationPackage(imp Import) *FileSpec {
	f.InitializationPackages = append(f.InitializationPackages, imp)
	return f
}

// CodeBlock adds a code block to the file
func (f *FileSpec) CodeBlock(blk CodeBlock) *FileSpec {
	f.CodeBlocks = append(f.CodeBlocks, blk)
	return f
}

// InitFunction assign an init function
func (f *FileSpec) InitFunction(blk *FuncSpec) *FileSpec {
	f.Init = blk
	return f
}

// GlobalVariable adds a global variable to the file with the given name, type reference, format string
// for the value of the variable, and arguments for the format string.
func (f *FileSpec) GlobalVariable(name string, typ TypeReference, format string, args ...interface{}) *FileSpec {
	v := &Variable{
		Identifier: Identifier{
			Name: name,
			Type: typ,
		},
		Constant: false,
		Format:   format,
		Args:     args,
	}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return f
}

// GlobalConstant adds a global constant to the file with the given name, type reference, format string
// for the value of the constant, and arguments for the format string.
func (f *FileSpec) GlobalConstant(name string, typ TypeReference, format string, args ...interface{}) *FileSpec {
	v := &Variable{
		Identifier: Identifier{
			Name: name,
			Type: typ,
		},
		Constant: true,
		Format:   format,
		Args:     args,
	}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return f
}

// VariableGrouping adds a variable grouping to the file, which can have variables appended to it
// that will be formatted in groups of variables and constants.
func (f *FileSpec) VariableGrouping() *VariableGrouping {
	v := &VariableGrouping{}
	f.CodeBlocks = append(f.CodeBlocks, v)
	return v
}
<|endoftext|>


<commit_before>package fuzzaldrin

import (
	"os"
	"strings"
)

// Score caliculates mathing score
func Score(str, query string) float64 {
	if str == "" {
		return 0
	}
	if query == "" {
		return 0
	}
	if str == query {
		return 2
	}

	queryHasSlashes := strings.Index(query, string(os.PathSeparator)) != -1
	str = strings.Replace(str, " ", "", -1)
	calcScore := score(str, query)
	if queryHasSlashes {
		calcScore = basenameScore(str, query, calcScore)
	}
	return calcScore
}
<commit_msg>Fix condition<commit_after>package fuzzaldrin

import (
	"os"
	"strings"
)

// Score caliculates mathing score
func Score(str, query string) float64 {
	if str == "" {
		return 0
	}
	if query == "" {
		return 0
	}
	if str == query {
		return 2
	}

	queryHasSlashes := strings.Index(query, string(os.PathSeparator)) != -1
	str = strings.Replace(str, " ", "", -1)
	calcScore := score(str, query)
	if !queryHasSlashes {
		calcScore = basenameScore(str, query, calcScore)
	}
	return calcScore
}
<|endoftext|>