<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"log"
	"math/big"
	"strings"
	"sync"
	"time"

	"github.com/go-mangos/mangos"
	"github.com/go-mangos/mangos/protocol/bus"
	"github.com/go-mangos/mangos/transport/tlstcp"
	"github.com/nictuku/dht"
)

type BusMessage struct {
	From    string
	To      string
	Seq     int64
	Cmd     string
	Payload string
}

func NewBusMessage(data []byte, err error) (*BusMessage, error) {
	if err != nil {
		return nil, err
	}

	rv := &BusMessage{}
	if err = json.Unmarshal(data, rv); err != nil {
		return nil, err
	}
	return rv, nil
}

func (b *BusMessage) String() string {
	return fmt.Sprintf("[%s: %v (ID: %d)]", b.Cmd, b.Payload, b.Seq)
}

func (b *BusMessage) Bytes() []byte {
	m, err := json.Marshal(b)
	if err != nil {
		log.Fatalf(`can't marshall bus message to json: %s`, err)
	}
	return m
}

type Friend struct {
	name     string
	msg      *BusMessage
	lastSeen time.Time
	mtx      *sync.Mutex
	pm       *PeerManager
}

func NewFriend(name string, pm *PeerManager) *Friend {
	return &Friend{name: name, mtx: &sync.Mutex{}, lastSeen: time.Now(), pm: pm}
}

func (f *Friend) String() string {
	f.mtx.Lock()
	defer f.mtx.Unlock()

	if f.msg == nil {
		return fmt.Sprintf(`%s: no message, last seen: %s`, f.name, f.lastSeen)
	}

	return fmt.Sprintf("%s: last message: %s, last seen: %s ago", f.name, f.msg, time.Now().Sub(f.lastSeen))
}

func (f *Friend) HandleMessage(m *BusMessage) {
	f.mtx.Lock()
	defer f.mtx.Unlock()

	if f.msg != nil && f.msg.Seq >= m.Seq {
		/* We've already seen this message */
		return
	}

	f.msg = m
	f.lastSeen = time.Now()

	switch m.Cmd {
	case "event":
		ev := Event{}
		if err := json.Unmarshal([]byte(m.Payload), &ev); err != nil {
			log.Printf(`can't unmarshal event payload: %s`, err)
		}
		log.Printf(`got an event: %v`, ev)

		if err := f.pm.db.MergeEvent(ev); err != nil {
			log.Printf(`can't merge event: %s`, err)
		}
	case "hello":
		f.pm.mtx.Lock()
		defer f.pm.mtx.Unlock()

		f.pm.need_full_sync = true
	case "i'm alive":
		/* nothing */
	default:
		log.Printf(`unhandled message: tgt: %s, src: %s, cmd: %s, payload: %v`, m.To, m.From, m.Cmd, m.Payload)
	}
}

type PeerManager struct {
	d              *dht.DHT
	db             *DB
	bus            mangos.Socket
	nick           string
	friends        map[string]*Friend
	oldfriends     map[string]*Friend
	venue          string
	sequence       int64
	need_full_sync bool
	opts           map[string]interface{}
	mtx            *sync.RWMutex
}

func NewPeerManager(db *DB) *PeerManager {
	conf := dht.NewConfig()
	conf.Port = 55000

	pm := PeerManager{db: db}

	pm.opts = map[string]interface{}{mangos.OptionTLSConfig: pm.setupTLS()}

	var err error
	pm.bus, err = bus.NewSocket()
	if err != nil {
		log.Fatalf(`can't create BUS socket: %s`, err)
	}
	pm.bus.AddTransport(tlstcp.NewTransport())

	if pm.d, err = dht.New(conf); err != nil {
		log.Fatalf(`can't create DHT: %s`, err)
	}

	sum := sha1.Sum([]byte("LetsMeetHere"))
	pm.venue = hex.EncodeToString(sum[:])

	buf := make([]byte, 4)
	rand.Read(buf)
	pm.nick = hex.EncodeToString(buf)

	log.Printf(`My nickname is %s`, pm.nick)
	log.Printf(`I will meet my friends at %s`, pm.venue)

	pm.friends = make(map[string]*Friend)
	pm.oldfriends = make(map[string]*Friend)

	pm.mtx = &sync.RWMutex{}

	return &pm
}

func (pm *PeerManager) setupTLS() *tls.Config {
	cert := pm.setupCertificate()

	return &tls.Config{
		InsecureSkipVerify: true,
		Certificates:       []tls.Certificate{cert},
	}
}

func (pm *PeerManager) setupCertificate() tls.Certificate {
	template := x509.Certificate{
		SerialNumber: big.NewInt(4711),
		Subject: pkix.Name{
			Organization: []string{"unobtanium"},
			CommonName:   "*",
		},
		DNSNames:              []string{`*`},
		NotAfter:              time.Now().AddDate(0, 0, 10),
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		SignatureAlgorithm:    x509.SHA512WithRSA,
		PublicKeyAlgorithm:    x509.ECDSA,
		SubjectKeyId:          []byte{1, 2, 3, 4, 5},
		BasicConstraintsValid: true,
		IsCA: true,
	}

	log.Printf(`generating 2048 bit RSA private key`)
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey
	log.Printf(`building self-signed certificate`)
	cert_raw, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
	if err != nil {
		log.Fatalf(`can't generate TLS certificate: %s`, err)
	}
	log.Printf(`created a cert of length %d bytes`, len(cert_raw))

	privbuf := &bytes.Buffer{}
	pem.Encode(privbuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	certbuf := &bytes.Buffer{}
	pem.Encode(certbuf, &pem.Block{Type: "CERTIFICATE", Bytes: cert_raw})

	cert, err := tls.X509KeyPair(certbuf.Bytes(), privbuf.Bytes())
	if err != nil {
		log.Fatalf(`can't build key pair: %s`, err)
	}

	return cert
}

func (pm *PeerManager) String() string {
	pm.mtx.RLock()
	defer pm.mtx.RUnlock()

	s := []string{
		fmt.Sprintf("DHT: Port: %d", pm.d.Port()),
		fmt.Sprintf("\r\nI am %s, my sequence ID is %d", pm.nick, pm.sequence),
		fmt.Sprintf("I have %d friend(s)", len(pm.friends)),
		fmt.Sprintf("We're meeting at '%s'", pm.venue),
		"\r\nThese are my friends:\r\n",
	}

	for _, f := range pm.friends {
		s = append(s, f.String())
	}

	s = append(s, "\r\nI haven't heard from these guys in a while:\r\n")
	for _, f := range pm.oldfriends {
		s = append(s, f.String())
	}

	return strings.Join(s, "\r\n")
}

func (pm *PeerManager) Publish(dst, cmd, payload string) error {
	pm.mtx.Lock()
	pm.sequence++
	m := &BusMessage{From: pm.nick, To: dst, Seq: pm.sequence, Cmd: cmd, Payload: payload}
	pm.mtx.Unlock()

	return pm.bus.Send(m.Bytes())
}

func (pm *PeerManager) Loop() {
	ih, err := dht.DecodeInfoHash(pm.venue)
	if err != nil {
		log.Printf(`can't decode infohash: %s`, err)
		return
	}

	if err := pm.d.Start(); err != nil {
		log.Printf(`can't start DHT: %s`, err)
		return
	}

	log.Printf(`DHT bound to port %d`, pm.d.Port())

	if err := pm.bus.ListenOptions(fmt.Sprintf("tls+tcp://*:%d", pm.d.Port()), pm.opts); err != nil {
		log.Fatalf(`can't listen on BUS socket: %s`, err)
	}

	go pm.drainPeers()

	go func() {
		for {
			time.Sleep(2 * time.Second)
			pm.mtx.Lock()
			for name, f := range pm.friends {
				f.mtx.Lock()
				if f.lastSeen.Add(10 * time.Second).Before(time.Now()) {
					log.Printf(`haven't heard from %s in a while`, name)
					pm.oldfriends[name] = f
					delete(pm.friends, name)
				}
				f.mtx.Unlock()
			}
			pm.mtx.Unlock()
		}
	}()

	go func() {
		for {
			/* Receive message */
			m, err := NewBusMessage(pm.bus.Recv())
			if err != nil {
				log.Printf(`can't receive message from bus: %s`, err)
				continue
			}

			/* Ignore messages from ourselves */
			if m.From == pm.nick {
				continue
			}

			/* Ignore messages not to 'everyone' or us */
			if m.To != pm.nick && m.To != "*" {
				continue
			}

			pm.mtx.Lock()
			f, ok := pm.friends[m.From]
			if !ok {
				f = NewFriend(m.From, pm)
				pm.friends[m.From] = f
				pm.need_full_sync = true
			}
			pm.mtx.Unlock()

			f.HandleMessage(m)

			if !ok {
				log.Printf(`%s is a new friend!`, m.From)
				pm.Publish(m.From, "hello", "")
			}
		}
	}()

	go func() {
		i := 0
		for {
			pm.Publish("*", "i'm alive", fmt.Sprintf("%d", i))
			i++
			time.Sleep(5 * time.Second)
		}
	}()

	go func() {
		for {
			buf, err := json.Marshal(<-pm.db.Events)
			if err != nil {
				log.Fatalf(`can't marshal event: %s`, err)
			}
			pm.Publish("*", "event", string(buf))
		}
	}()

	go func() {
		for {
			time.Sleep(5 * time.Second)
			pm.mtx.Lock()
			if !pm.need_full_sync {
				pm.mtx.Unlock()
				continue
			}
			pm.need_full_sync = false
			pm.mtx.Unlock()

			log.Println(`doing a full sync`)

			for _, env := range pm.db.AllEnvelopes() {
				_, events, err := pm.db.EnvelopeWithHistory(env.Id)
				if err != nil {
					log.Fatalf(`can't get events for envelope %s: %s`, env.Id, err)
				}
				for _, e := range events {
					pm.db.Events <- e
				}
			}
		}
	}()

	for {
		pm.d.PeersRequest(string(ih), true)
		time.Sleep(5 * time.Second)
	}
}

func (pm *PeerManager) drainPeers() {
	log.Printf(`draining DHT`)
	seen := make(map[string]struct{})

	for r := range pm.d.PeersRequestResults {
		for _, peers := range r {
			for _, x := range peers {
				addr := dht.DecodePeerAddress(x)
				if _, ok := seen[addr]; !ok {
					pm.connectToPeer(addr)
				}
				seen[addr] = struct{}{}
			}
		}
	}
}

func (pm *PeerManager) connectToPeer(addr string) {
	if err := pm.bus.DialOptions(fmt.Sprintf("tls+tcp://%s", addr), pm.opts); err != nil {
		log.Printf(`can't connect SUB to %s: %s`, addr, err)
	}
}
<commit_msg>Log outgoing connectinos<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"log"
	"math/big"
	"strings"
	"sync"
	"time"

	"github.com/go-mangos/mangos"
	"github.com/go-mangos/mangos/protocol/bus"
	"github.com/go-mangos/mangos/transport/tlstcp"
	"github.com/nictuku/dht"
)

type BusMessage struct {
	From    string
	To      string
	Seq     int64
	Cmd     string
	Payload string
}

func NewBusMessage(data []byte, err error) (*BusMessage, error) {
	if err != nil {
		return nil, err
	}

	rv := &BusMessage{}
	if err = json.Unmarshal(data, rv); err != nil {
		return nil, err
	}
	return rv, nil
}

func (b *BusMessage) String() string {
	return fmt.Sprintf("[%s: %v (ID: %d)]", b.Cmd, b.Payload, b.Seq)
}

func (b *BusMessage) Bytes() []byte {
	m, err := json.Marshal(b)
	if err != nil {
		log.Fatalf(`can't marshall bus message to json: %s`, err)
	}
	return m
}

type Friend struct {
	name     string
	msg      *BusMessage
	lastSeen time.Time
	mtx      *sync.Mutex
	pm       *PeerManager
}

func NewFriend(name string, pm *PeerManager) *Friend {
	return &Friend{name: name, mtx: &sync.Mutex{}, lastSeen: time.Now(), pm: pm}
}

func (f *Friend) String() string {
	f.mtx.Lock()
	defer f.mtx.Unlock()

	if f.msg == nil {
		return fmt.Sprintf(`%s: no message, last seen: %s`, f.name, f.lastSeen)
	}

	return fmt.Sprintf("%s: last message: %s, last seen: %s ago", f.name, f.msg, time.Now().Sub(f.lastSeen))
}

func (f *Friend) HandleMessage(m *BusMessage) {
	f.mtx.Lock()
	defer f.mtx.Unlock()

	if f.msg != nil && f.msg.Seq >= m.Seq {
		/* We've already seen this message */
		return
	}

	f.msg = m
	f.lastSeen = time.Now()

	switch m.Cmd {
	case "event":
		ev := Event{}
		if err := json.Unmarshal([]byte(m.Payload), &ev); err != nil {
			log.Printf(`can't unmarshal event payload: %s`, err)
		}
		log.Printf(`got an event: %v`, ev)

		if err := f.pm.db.MergeEvent(ev); err != nil {
			log.Printf(`can't merge event: %s`, err)
		}
	case "hello":
		f.pm.mtx.Lock()
		defer f.pm.mtx.Unlock()

		f.pm.need_full_sync = true
	case "i'm alive":
		/* nothing */
	default:
		log.Printf(`unhandled message: tgt: %s, src: %s, cmd: %s, payload: %v`, m.To, m.From, m.Cmd, m.Payload)
	}
}

type PeerManager struct {
	d              *dht.DHT
	db             *DB
	bus            mangos.Socket
	nick           string
	friends        map[string]*Friend
	oldfriends     map[string]*Friend
	venue          string
	sequence       int64
	need_full_sync bool
	opts           map[string]interface{}
	mtx            *sync.RWMutex
}

func NewPeerManager(db *DB) *PeerManager {
	conf := dht.NewConfig()
	conf.Port = 55000

	pm := PeerManager{db: db}

	pm.opts = map[string]interface{}{mangos.OptionTLSConfig: pm.setupTLS()}

	var err error
	pm.bus, err = bus.NewSocket()
	if err != nil {
		log.Fatalf(`can't create BUS socket: %s`, err)
	}
	pm.bus.AddTransport(tlstcp.NewTransport())

	if pm.d, err = dht.New(conf); err != nil {
		log.Fatalf(`can't create DHT: %s`, err)
	}

	sum := sha1.Sum([]byte("LetsMeetHere"))
	pm.venue = hex.EncodeToString(sum[:])

	buf := make([]byte, 4)
	rand.Read(buf)
	pm.nick = hex.EncodeToString(buf)

	log.Printf(`My nickname is %s`, pm.nick)
	log.Printf(`I will meet my friends at %s`, pm.venue)

	pm.friends = make(map[string]*Friend)
	pm.oldfriends = make(map[string]*Friend)

	pm.mtx = &sync.RWMutex{}

	return &pm
}

func (pm *PeerManager) setupTLS() *tls.Config {
	cert := pm.setupCertificate()

	return &tls.Config{
		InsecureSkipVerify: true,
		Certificates:       []tls.Certificate{cert},
	}
}

func (pm *PeerManager) setupCertificate() tls.Certificate {
	template := x509.Certificate{
		SerialNumber: big.NewInt(4711),
		Subject: pkix.Name{
			Organization: []string{"unobtanium"},
			CommonName:   "*",
		},
		DNSNames:              []string{`*`},
		NotAfter:              time.Now().AddDate(0, 0, 10),
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		SignatureAlgorithm:    x509.SHA512WithRSA,
		PublicKeyAlgorithm:    x509.ECDSA,
		SubjectKeyId:          []byte{1, 2, 3, 4, 5},
		BasicConstraintsValid: true,
		IsCA: true,
	}

	log.Printf(`generating 2048 bit RSA private key`)
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey
	log.Printf(`building self-signed certificate`)
	cert_raw, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
	if err != nil {
		log.Fatalf(`can't generate TLS certificate: %s`, err)
	}
	log.Printf(`created a cert of length %d bytes`, len(cert_raw))

	privbuf := &bytes.Buffer{}
	pem.Encode(privbuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	certbuf := &bytes.Buffer{}
	pem.Encode(certbuf, &pem.Block{Type: "CERTIFICATE", Bytes: cert_raw})

	cert, err := tls.X509KeyPair(certbuf.Bytes(), privbuf.Bytes())
	if err != nil {
		log.Fatalf(`can't build key pair: %s`, err)
	}

	return cert
}

func (pm *PeerManager) String() string {
	pm.mtx.RLock()
	defer pm.mtx.RUnlock()

	s := []string{
		fmt.Sprintf("DHT: Port: %d", pm.d.Port()),
		fmt.Sprintf("\r\nI am %s, my sequence ID is %d", pm.nick, pm.sequence),
		fmt.Sprintf("I have %d friend(s)", len(pm.friends)),
		fmt.Sprintf("We're meeting at '%s'", pm.venue),
		"\r\nThese are my friends:\r\n",
	}

	for _, f := range pm.friends {
		s = append(s, f.String())
	}

	s = append(s, "\r\nI haven't heard from these guys in a while:\r\n")
	for _, f := range pm.oldfriends {
		s = append(s, f.String())
	}

	return strings.Join(s, "\r\n")
}

func (pm *PeerManager) Publish(dst, cmd, payload string) error {
	pm.mtx.Lock()
	pm.sequence++
	m := &BusMessage{From: pm.nick, To: dst, Seq: pm.sequence, Cmd: cmd, Payload: payload}
	pm.mtx.Unlock()

	return pm.bus.Send(m.Bytes())
}

func (pm *PeerManager) Loop() {
	ih, err := dht.DecodeInfoHash(pm.venue)
	if err != nil {
		log.Printf(`can't decode infohash: %s`, err)
		return
	}

	if err := pm.d.Start(); err != nil {
		log.Printf(`can't start DHT: %s`, err)
		return
	}

	log.Printf(`DHT bound to port %d`, pm.d.Port())

	if err := pm.bus.ListenOptions(fmt.Sprintf("tls+tcp://*:%d", pm.d.Port()), pm.opts); err != nil {
		log.Fatalf(`can't listen on BUS socket: %s`, err)
	}

	go pm.drainPeers()

	go func() {
		for {
			time.Sleep(2 * time.Second)
			pm.mtx.Lock()
			for name, f := range pm.friends {
				f.mtx.Lock()
				if f.lastSeen.Add(10 * time.Second).Before(time.Now()) {
					log.Printf(`haven't heard from %s in a while`, name)
					pm.oldfriends[name] = f
					delete(pm.friends, name)
				}
				f.mtx.Unlock()
			}
			pm.mtx.Unlock()
		}
	}()

	go func() {
		for {
			/* Receive message */
			m, err := NewBusMessage(pm.bus.Recv())
			if err != nil {
				log.Printf(`can't receive message from bus: %s`, err)
				continue
			}

			/* Ignore messages from ourselves */
			if m.From == pm.nick {
				continue
			}

			/* Ignore messages not to 'everyone' or us */
			if m.To != pm.nick && m.To != "*" {
				continue
			}

			pm.mtx.Lock()
			f, ok := pm.friends[m.From]
			if !ok {
				f = NewFriend(m.From, pm)
				pm.friends[m.From] = f
				pm.need_full_sync = true
			}
			pm.mtx.Unlock()

			f.HandleMessage(m)

			if !ok {
				log.Printf(`%s is a new friend!`, m.From)
				pm.Publish(m.From, "hello", "")
			}
		}
	}()

	go func() {
		i := 0
		for {
			pm.Publish("*", "i'm alive", fmt.Sprintf("%d", i))
			i++
			time.Sleep(5 * time.Second)
		}
	}()

	go func() {
		for {
			buf, err := json.Marshal(<-pm.db.Events)
			if err != nil {
				log.Fatalf(`can't marshal event: %s`, err)
			}
			pm.Publish("*", "event", string(buf))
		}
	}()

	go func() {
		for {
			time.Sleep(5 * time.Second)
			pm.mtx.Lock()
			if !pm.need_full_sync {
				pm.mtx.Unlock()
				continue
			}
			pm.need_full_sync = false
			pm.mtx.Unlock()

			log.Println(`doing a full sync`)

			for _, env := range pm.db.AllEnvelopes() {
				_, events, err := pm.db.EnvelopeWithHistory(env.Id)
				if err != nil {
					log.Fatalf(`can't get events for envelope %s: %s`, env.Id, err)
				}
				for _, e := range events {
					pm.db.Events <- e
				}
			}
		}
	}()

	for {
		pm.d.PeersRequest(string(ih), true)
		time.Sleep(5 * time.Second)
	}
}

func (pm *PeerManager) drainPeers() {
	log.Printf(`draining DHT`)
	seen := make(map[string]struct{})

	for r := range pm.d.PeersRequestResults {
		for _, peers := range r {
			for _, x := range peers {
				addr := dht.DecodePeerAddress(x)
				if _, ok := seen[addr]; !ok {
					pm.connectToPeer(addr)
				}
				seen[addr] = struct{}{}
			}
		}
	}
}

func (pm *PeerManager) connectToPeer(addr string) {
	log.Printf(`dialing %s`, addr)
	if err := pm.bus.DialOptions(fmt.Sprintf("tls+tcp://%s", addr), pm.opts); err != nil {
		log.Printf(`can't connect SUB to %s: %s`, addr, err)
	}
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/urfave/cli"
)

var psCommand = cli.Command{
	Name:      "ps",
	Usage:     "ps displays the processes running inside a container",
	ArgsUsage: `<container-id> [-- ps options]`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Value: "",
			Usage: `select one of: ` + formatOptions,
		},
	},
	Action: func(context *cli.Context) error {
		container, err := getContainer(context)
		if err != nil {
			return err
		}

		pids, err := container.Processes()
		if err != nil {
			return err
		}

		if context.String("format") == "json" {
			if err := json.NewEncoder(os.Stdout).Encode(pids); err != nil {
				return err
			}
			return nil
		}

		psArgs := context.Args().Get(1)
		if psArgs == "--" {
			psArgs = context.Args().Get(2)
		}
		if psArgs == "" {
			psArgs = "-ef"
		}

		output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
		if err != nil {
			return err
		}

		lines := strings.Split(string(output), "\n")
		pidIndex, err := getPidIndex(lines[0])
		if err != nil {
			return err
		}

		fmt.Println(lines[0])
		for _, line := range lines[1:] {
			if len(line) == 0 {
				continue
			}
			fields := strings.Fields(line)
			p, err := strconv.Atoi(fields[pidIndex])
			if err != nil {
				return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err)
			}

			for _, pid := range pids {
				if pid == p {
					fmt.Println(line)
					break
				}
			}
		}
		return nil
	},
}

func getPidIndex(title string) (int, error) {
	titles := strings.Fields(title)

	pidIndex := -1
	for i, name := range titles {
		if name == "PID" {
			return i, nil
		}
	}

	return pidIndex, fmt.Errorf("couldn't find PID field in ps output")
}
<commit_msg>ps: Support muitiple ps arguments<commit_after>// +build linux

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/urfave/cli"
)

var psCommand = cli.Command{
	Name:      "ps",
	Usage:     "ps displays the processes running inside a container",
	ArgsUsage: `<container-id> [-- ps options]`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Value: "",
			Usage: `select one of: ` + formatOptions,
		},
	},
	Action: func(context *cli.Context) error {
		container, err := getContainer(context)
		if err != nil {
			return err
		}

		pids, err := container.Processes()
		if err != nil {
			return err
		}

		if context.String("format") == "json" {
			if err := json.NewEncoder(os.Stdout).Encode(pids); err != nil {
				return err
			}
			return nil
		}

		// [1:] is to remove command name, ex:
		// context.Args(): [containet_id ps_arg1 ps_arg2 ...]
		// psArgs:         [ps_arg1 ps_arg2 ...]
		//
		psArgs := context.Args()[1:]

		if len(psArgs) > 0 && psArgs[0] == "--" {
			psArgs = psArgs[1:]
		}

		if len(psArgs) == 0 {
			psArgs = []string{"-ef"}
		}

		output, err := exec.Command("ps", psArgs...).Output()
		if err != nil {
			return err
		}

		lines := strings.Split(string(output), "\n")
		pidIndex, err := getPidIndex(lines[0])
		if err != nil {
			return err
		}

		fmt.Println(lines[0])
		for _, line := range lines[1:] {
			if len(line) == 0 {
				continue
			}
			fields := strings.Fields(line)
			p, err := strconv.Atoi(fields[pidIndex])
			if err != nil {
				return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err)
			}

			for _, pid := range pids {
				if pid == p {
					fmt.Println(line)
					break
				}
			}
		}
		return nil
	},
}

func getPidIndex(title string) (int, error) {
	titles := strings.Fields(title)

	pidIndex := -1
	for i, name := range titles {
		if name == "PID" {
			return i, nil
		}
	}

	return pidIndex, fmt.Errorf("couldn't find PID field in ps output")
}
<|endoftext|>


<commit_before>package qq

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

type color string

const (
	bold     color = "\033[1m"
	yellow   color = "\033[33m"
	cyan     color = "\033[36m"
	endColor color = "\033[0m" // ANSI escape code for "reset everything"
)

var (
	// LogFile is the full path to the qq.log file.
	LogFile string
	logger  *log.Logger
)

func init() {
	LogFile = filepath.Join(os.TempDir(), "qq.log")

	// init with stderr. will be replaced with qq.log on every print.
	// this is necessary so log file can be properly closed after printing.
	logger = log.New(os.Stderr, "", 0)
}

func openLog() *os.File {
	fd, err := os.OpenFile(LogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		panic(err)
	}
	return fd
}

func Log(a ...interface{}) {
	// get info about parent func calling qq.Log()
	pc, file, line, ok := runtime.Caller(1)
	if ok {
		names, err := argNames(file, line)
		if err == nil {
			a = formatArgs(names, a)
		}

		logger.SetPrefix(prefix(pc, file, line))
	}
	a = append(a, "\n") // extra space between logs

	l := openLog()
	defer l.Close()
	logger.SetOutput(l)
	logger.Println(a...)
}

// func Print(a ...interface{}) {

// }

// func Println(a ...interface{}) {

// }

// func Printf(format string, a ...interface{}) {
// 	f := filepath.Join(os.TempDir(), LogFile)
// 	fd, err := os.OpenFile(f, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
// 	if err != nil {
// 		panic(err)
// 	}
// 	defer fd.Close()

// 	pc, file, line, ok := runtime.Caller(1)
// 	if !ok {
// 		mu.Lock()
// 		defer mu.Unlock()
// 		_, err = fmt.Fprintf(fd, format, a...)
// 		return
// 	}

// 	p := prefix(pc, file, line)
// 	mu.Lock()
// 	defer mu.Unlock()
// 	_, err = fmt.Fprintf(fd, p+" "+format, a...)

// 	if err != nil {
// 		panic(err)
// 	}
// }

func prefix(pc uintptr, file string, line int) string {
	t := time.Now().Format("15:04:05")
	shortFile := filepath.Base(file)
	callerName := runtime.FuncForPC(pc).Name()

	return fmt.Sprintf("[%s %s:%d %s] ", t, shortFile, line, callerName)
}

// formatArgs turns a slice of arguments into pretty-printed strings. If the
// argument is a variable or an expression, it will be returned as a
// name=value string, e.g. "port=443", "3+2=5". Variable names, expressions, and
// values are colorized using ANSI escape codes.
func formatArgs(names []string, values []interface{}) []interface{} {
	for i := 0; i < len(values); i++ {
		v := fmt.Sprintf("%#v", values[i])
		colorizedVal := cyan + v + endColor
		if names[i] == "" {
			// arg is a literal
			values[i] = colorizedVal
		} else {
			colorizedName := bold + names[i] + endColor
			values[i] = fmt.Sprintf("%s=%s", colorizedName, colorizedVal)
		}
	}
	return values
}

// argNames returns the names of all the variable arguments for the qq.Print*()
// call at the given file and line number. If the argument is not a variable,
// the slice will contain an empty string at the index position for that
// argument. For example, qq.Print(a, 123) will result in []string{"a", ""}
// for arg names, because 123 is not a variable name.
func argNames(file string, line int) ([]string, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, file, nil, 0)
	if err != nil {
		return nil, err
	}

	var names []string
	ast.Inspect(f, func(n ast.Node) bool {
		call, is := n.(*ast.CallExpr)
		if !is {
			return true // visit next node
		}

		if fset.Position(call.End()).Line != line {
			return true
		}

		if !qqCall(call) {
			return true
		}

		for _, arg := range call.Args {
			names = append(names, argName(arg))
		}
		return true
	})

	return names, nil
}

// qqCall returns true if the given function call expression is for a qq
// function, e.g. qq.Log().
func qqCall(n *ast.CallExpr) bool {
	sel, is := n.Fun.(*ast.SelectorExpr)
	if !is {
		return false
	}

	ident, is := sel.X.(*ast.Ident)
	if !is {
		return false
	}

	return ident.Name == "qq"
}

// exprString returns the source text underlying the given ast.Expr.
func exprString(arg ast.Expr) string {
	var buf bytes.Buffer
	fset := token.NewFileSet()
	printer.Fprint(&buf, fset, arg)
	return buf.String() // returns empty string if printer fails
}

// argName returns the name of the given argument if it's a variable. If the
// argument is something else, like a literal or a function call, argName
// returns an empty string.
func argName(arg ast.Expr) string {
	var name string
	switch a := arg.(type) {
	case *ast.Ident:
		if a.Obj.Kind == ast.Var {
			name = a.Obj.Name
		}
	case *ast.BinaryExpr,
		*ast.CallExpr,
		*ast.IndexExpr,
		*ast.KeyValueExpr,
		*ast.ParenExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.UnaryExpr:
		name = exprString(arg)
	}
	return name
}
<commit_msg>remove init()<commit_after>package qq

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

type color string

const (
	bold     color = "\033[1m"
	yellow   color = "\033[33m"
	cyan     color = "\033[36m"
	endColor color = "\033[0m" // ANSI escape code for "reset everything"
)

var (
	// LogFile is the full path to the qq.log file.
	LogFile = filepath.Join(os.TempDir(), "qq.log")

	// init with stderr. will be replaced with qq.log on every print.
	// this is necessary so log file can be properly closed after printing.
	logger = log.New(os.Stderr, "", 0)

	// for grouping log messages by time of write
	timer = time.NewTimer(0)
)

func Log(a ...interface{}) {
	// get info about parent func calling qq.Log()
	pc, file, line, ok := runtime.Caller(1)
	if ok {
		names, err := argNames(file, line)
		if err == nil {
			a = formatArgs(names, a)
		}

		logger.SetPrefix(prefix(pc, file, line))
	}
	a = append(a, "\n") // extra space between logs

	l := openLog()
	defer l.Close()
	logger.SetOutput(l)
	logger.Println(a...)
}

// func Print(a ...interface{}) {

// }

// func Println(a ...interface{}) {

// }

// func Printf(format string, a ...interface{}) {
// 	f := filepath.Join(os.TempDir(), LogFile)
// 	fd, err := os.OpenFile(f, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
// 	if err != nil {
// 		panic(err)
// 	}
// 	defer fd.Close()

// 	pc, file, line, ok := runtime.Caller(1)
// 	if !ok {
// 		mu.Lock()
// 		defer mu.Unlock()
// 		_, err = fmt.Fprintf(fd, format, a...)
// 		return
// 	}

// 	p := prefix(pc, file, line)
// 	mu.Lock()
// 	defer mu.Unlock()
// 	_, err = fmt.Fprintf(fd, p+" "+format, a...)

// 	if err != nil {
// 		panic(err)
// 	}
// }

func prefix(pc uintptr, file string, line int) string {
	t := time.Now().Format("15:04:05")
	shortFile := filepath.Base(file)
	callerName := runtime.FuncForPC(pc).Name()

	return fmt.Sprintf("[%s %s:%d %s] ", t, shortFile, line, callerName)
}

// formatArgs turns a slice of arguments into pretty-printed strings. If the
// argument is a variable or an expression, it will be returned as a
// name=value string, e.g. "port=443", "3+2=5". Variable names, expressions, and
// values are colorized using ANSI escape codes.
func formatArgs(names []string, values []interface{}) []interface{} {
	for i := 0; i < len(values); i++ {
		v := fmt.Sprintf("%#v", values[i])
		colorizedVal := cyan + v + endColor
		if names[i] == "" {
			// arg is a literal
			values[i] = colorizedVal
		} else {
			colorizedName := bold + names[i] + endColor
			values[i] = fmt.Sprintf("%s=%s", colorizedName, colorizedVal)
		}
	}
	return values
}

// argNames returns the names of all the variable arguments for the qq.Print*()
// call at the given file and line number. If the argument is not a variable,
// the slice will contain an empty string at the index position for that
// argument. For example, qq.Print(a, 123) will result in []string{"a", ""}
// for arg names, because 123 is not a variable name.
func argNames(file string, line int) ([]string, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, file, nil, 0)
	if err != nil {
		return nil, err
	}

	var names []string
	ast.Inspect(f, func(n ast.Node) bool {
		call, is := n.(*ast.CallExpr)
		if !is {
			return true // visit next node
		}

		if fset.Position(call.End()).Line != line {
			return true
		}

		if !qqCall(call) {
			return true
		}

		for _, arg := range call.Args {
			names = append(names, argName(arg))
		}
		return true
	})

	return names, nil
}

// qqCall returns true if the given function call expression is for a qq
// function, e.g. qq.Log().
func qqCall(n *ast.CallExpr) bool {
	sel, is := n.Fun.(*ast.SelectorExpr)
	if !is {
		return false
	}

	ident, is := sel.X.(*ast.Ident)
	if !is {
		return false
	}

	return ident.Name == "qq"
}

// exprString returns the source text underlying the given ast.Expr.
func exprString(arg ast.Expr) string {
	var buf bytes.Buffer
	fset := token.NewFileSet()
	printer.Fprint(&buf, fset, arg)
	return buf.String() // returns empty string if printer fails
}

// argName returns the name of the given argument if it's a variable. If the
// argument is something else, like a literal or a function call, argName
// returns an empty string.
func argName(arg ast.Expr) string {
	var name string
	switch a := arg.(type) {
	case *ast.Ident:
		if a.Obj.Kind == ast.Var {
			name = a.Obj.Name
		}
	case *ast.BinaryExpr,
		*ast.CallExpr,
		*ast.IndexExpr,
		*ast.KeyValueExpr,
		*ast.ParenExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.UnaryExpr:
		name = exprString(arg)
	}
	return name
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

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

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

package obcca

import (
	"testing"
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
	"sync"
	"io/ioutil"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
	"golang.org/x/net/context"
	google_protobuf "google/protobuf"

	"github.com/openblockchain/obc-peer/openchain"
	"github.com/openblockchain/obc-peer/openchain/chaincode"
	"github.com/openblockchain/obc-peer/openchain/consensus/helper"
	"github.com/openblockchain/obc-peer/openchain/ledger/genesis"
	"github.com/openblockchain/obc-peer/openchain/peer"
	"github.com/openblockchain/obc-peer/openchain/rest"
	pb "github.com/openblockchain/obc-peer/protos"
	"github.com/openblockchain/obc-peer/openchain/ledger"

	"encoding/json"
	//"errors"
	//"runtime"
	//"strings"
	//"github.com/howeyc/gopass"
	//"github.com/op/go-logging"
	//"github.com/spf13/cobra"
	//"github.com/openblockchain/obc-peer/events/producer"
)

var (
	tca *TCA
	eca *ECA
)

type ValidityPeriod struct {
	Name  string
	Value string
}

func TestMain(m *testing.M) {
	setupTestConfig()
	os.Exit(m.Run())
}

func setupTestConfig() {
	viper.AutomaticEnv()
	viper.SetConfigName("obcca_test") // name of config file (without extension)
	viper.AddConfigPath("./")         // path to look for the config file in
	viper.AddConfigPath("./..")       // path to look for the config file in
	err := viper.ReadInConfig()       // Find and read the config file
	if err != nil {                   // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
}

func TestValidityPeriod(t *testing.T) {
	var updateInterval int64
	updateInterval = 37

	// 1. Start TCA and Openchain
	go startServices(t)

	// 2. Obtain the validity period by querying and directly from the ledger
	validityPeriod_A := queryValidityPeriod(t)
	validityPeriodFromLedger_A := getValidityPeriodFromLedger(t)

	// 3. Wait for the validity period to be updated...
	time.Sleep(time.Second * 40)

	// ... and read the values again
	validityPeriod_B := queryValidityPeriod(t)
	validityPeriodFromLedger_B := getValidityPeriodFromLedger(t)

	// 5. Stop TCA and Openchain
	stopServices()

	// 6. Compare the values
	if validityPeriod_A != validityPeriodFromLedger_A {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_A, validityPeriodFromLedger_A)
		t.Fail()
	}

	if validityPeriod_B != validityPeriodFromLedger_B {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_B, validityPeriodFromLedger_B)
		t.Fail()
	}

	if validityPeriod_B - validityPeriod_A != updateInterval {
		t.Logf("Validity period difference must be equal to the update interval. Expected: %s, Actual: %s", updateInterval, validityPeriod_B - validityPeriod_A)
		t.Fail()
	}

	// 7. cleanup tca and openchain folders
	if err := os.RemoveAll(viper.GetString("peer.fileSystemPath")); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", viper.GetString("peer.fileSystemPath"), err)
	}
	if err := os.RemoveAll(".obcca"); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", ".obcca", err)
	}
}

func startServices(t *testing.T) {
	go startTCA()
	err := startOpenchain()
	if(err != nil){
		t.Logf("Error starting Openchain: %s", err)
		t.Fail()
	}
}

func stopServices(){
	stopOpenchain()
	stopTCA()
}

func startTCA() {
	LogInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr, os.Stdout)

	eca = NewECA()
	defer eca.Close()

	tca = NewTCA(eca)
	defer tca.Close()

	var wg sync.WaitGroup
	eca.Start(&wg)
	tca.Start(&wg)

	wg.Wait()
}

func stopTCA(){
	tca.Stop()
	eca.Stop()
}

func queryValidityPeriod(t *testing.T) int64 {
	url := "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update"
	version := "0.0.1"
	args := []string{"system.validity.period"}

	validityPeriod, err := queryTransaction(url, version, args)
	if err != nil {
		t.Logf("Failed querying validity period: %s", err)
		t.Fail()
	}

	var vp ValidityPeriod
	json.Unmarshal(validityPeriod, &vp)

	value, err := strconv.ParseInt(vp.Value, 10, 64)
	if err != nil {
		t.Logf("Failed parsing validity period: %s", err)
		t.Fail()
	}

	return value
}

func getValidityPeriodFromLedger(t *testing.T) int64 {
	chaincodeID := &pb.ChaincodeID{Url: "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update",
		Version: "0.0.1",
	}

	cid, _ := getChaincodeID(chaincodeID)

	ledger, err := ledger.GetLedger()
	if err != nil {
		t.Logf("Failed getting access to the ledger: %s", err)
		t.Fail()
	}

	vp_bytes, err := ledger.GetState(cid, "system.validity.period", true)
	if err != nil {
		t.Logf("Failed reading validity period from the ledger: %s", err)
		t.Fail()
	}

	i, err := strconv.ParseInt(string(vp_bytes[:]), 10, 64)
	if err != nil {
		t.Logf("Failed to parse validity period: %s", err)
		t.Fail()
	}

	return i
 }

// getChaincodeID constructs the ID from pb.ChaincodeID; used by handlerMap
func getChaincodeID(cID *pb.ChaincodeID) (string, error) {
	if cID == nil {
		return "", fmt.Errorf("Cannot construct chaincodeID, got nil object")
	}
	var urlLocation string
	if strings.HasPrefix(cID.Url, "http://") {
		urlLocation = cID.Url[7:]
	} else if strings.HasPrefix(cID.Url, "https://") {
		urlLocation = cID.Url[8:]
	} else {
		urlLocation = cID.Url
	}
	return urlLocation + ":" + cID.Version, nil
}

func queryTransaction(url string, version string, args []string) ([]byte, error) {

	chaincodeInvocationSpec := createChaincodeInvocationForQuery(args, url, version, "system_chaincode_invoker")

	fmt.Printf("Going to query\n")

	response, err := queryChaincode(chaincodeInvocationSpec)

	if err != nil {
		return nil, fmt.Errorf("Error querying <%s>: %s", url, err)
	}

	logger.Info("Successfully invoked validity period update: %s(%s)", url, string(response.Msg))

	return response.Msg, nil
}

func queryChaincode(chaincodeInvSpec *pb.ChaincodeInvocationSpec) (*pb.Response, error) {

	devopsClient, err := getDevopsClient(viper.GetString("pki.validity-period.devops-address"))
	if err != nil {
		logger.Error(fmt.Sprintf("Error retrieving devops client: %s", err))
		return nil,err
	}

	resp, err := devopsClient.Query(context.Background(), chaincodeInvSpec)

	if err != nil {
		logger.Error(fmt.Sprintf("Error invoking validity period update system chaincode: %s", err))
		return nil,err
	}

	logger.Info("Successfully invoked validity period update: %s(%s)", chaincodeInvSpec, string(resp.Msg))

	return resp,nil
}

func createChaincodeInvocationForQuery(arguments []string, chaincodePath string, chaincodeVersion string, token string) *pb.ChaincodeInvocationSpec {
	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
		ChaincodeID: &pb.ChaincodeID{Url: chaincodePath,
			Version: chaincodeVersion,
		},
		CtorMsg: &pb.ChaincodeInput{Function: "query",
			Args: arguments,
		},
	}

	spec.SecureContext = string(token)

	invocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}

	return invocationSpec
}

func startOpenchain() error {

	peerEndpoint, err := peer.GetPeerEndpoint()
	if err != nil {
		logger.Error(fmt.Sprintf("Failed to get Peer Endpoint: %s", err))
		return err
	}

	listenAddr := viper.GetString("peer.listenaddress")

	if "" == listenAddr {
		logger.Debug("Listen address not specified, using peer endpoint address")
		listenAddr = peerEndpoint.Address
	}

	lis, err := net.Listen("tcp", listenAddr)
	if err != nil {
		grpclog.Fatalf("failed to listen: %v", err)
	}

//	ehubLis, ehubGrpcServer, err := createEventHubServer()
//	if err != nil {
//		grpclog.Fatalf("failed to create ehub server: %v", err)
//	}

	logger.Info("Security enabled status: %t", viper.GetBool("security.enabled"))

	var opts []grpc.ServerOption
	if viper.GetBool("peer.tls.enabled") {
		creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"), viper.GetString("peer.tls.key.file"))
		if err != nil {
			grpclog.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}

	grpcServer := grpc.NewServer(opts...)

	// Register the Peer server
	//pb.RegisterPeerServer(grpcServer, openchain.NewPeer())
	var peerServer *peer.PeerImpl

	if viper.GetBool("peer.validator.enabled") {
		logger.Debug("Running as validating peer - installing consensus %s", viper.GetString("peer.validator.consensus"))
		peerServer, _ = peer.NewPeerWithHandler(helper.NewConsensusHandler)
	} else {
		logger.Debug("Running as non-validating peer")
		peerServer, _ = peer.NewPeerWithHandler(peer.NewPeerHandler)
	}
	pb.RegisterPeerServer(grpcServer, peerServer)

	// Register the Admin server
	pb.RegisterAdminServer(grpcServer, openchain.NewAdminServer())

	// Register ChaincodeSupport server...
	// TODO : not the "DefaultChain" ... we have to revisit when we do multichain
	registerChaincodeSupport(chaincode.DefaultChain, grpcServer)

	// Register Devops server
	serverDevops := openchain.NewDevopsServer(peerServer)
	pb.RegisterDevopsServer(grpcServer, serverDevops)

	// Register the ServerOpenchain server
	serverOpenchain, err := openchain.NewOpenchainServer()
	if err != nil {
		logger.Error(fmt.Sprintf("Error creating OpenchainServer: %s", err))
		return err
	}

	pb.RegisterOpenchainServer(grpcServer, serverOpenchain)

	// Create and register the REST service
	go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)

	rootNode, err := openchain.GetRootNode()
	if err != nil {
		grpclog.Fatalf("Failed to get peer.discovery.rootnode valey: %s", err)
	}

	logger.Info("Starting peer with id=%s, network id=%s, address=%s, discovery.rootnode=%s, validator=%v",
		peerEndpoint.ID, viper.GetString("peer.networkId"),
		peerEndpoint.Address, rootNode, viper.GetBool("peer.validator.enabled"))

	// Start the grpc server. Done in a goroutine so we can deploy the
	// genesis block if needed.
	serve := make(chan bool)
	go func() {
		grpcServer.Serve(lis)
		serve <- true
	}()

	// Deploy the geneis block if needed.
	if viper.GetBool("peer.validator.enabled") {
		makeGeneisError := genesis.MakeGenesis(peerServer.GetSecHelper())
		if makeGeneisError != nil {
			return makeGeneisError
		}
	}

	//start the event hub server
//	if ehubGrpcServer != nil && ehubLis != nil {
//		go ehubGrpcServer.Serve(ehubLis)
//	}

	// Block until grpc server exits
	<-serve

	return nil
}

func stopOpenchain() {
	clientConn, err := peer.NewPeerClientConnection()
	if err != nil {
		logger.Error("Error trying to connect to local peer:", err)
		return
	}

	logger.Info("Stopping peer...")
	serverClient := pb.NewAdminClient(clientConn)

	status, err := serverClient.StopServer(context.Background(), &google_protobuf.Empty{})
	logger.Info("Current status: %s", status)

}

func registerChaincodeSupport(chainname chaincode.ChainName, grpcServer *grpc.Server) {
	//get user mode
	userRunsCC := false
	if viper.GetString("chaincode.mode") == chaincode.DevModeUserRunsChaincode {
		userRunsCC = true
	}

	//get chaincode startup timeout
	tOut, err := strconv.Atoi(viper.GetString("chaincode.startuptimeout"))
	if err != nil { //what went wrong ?
		fmt.Printf("could not retrive timeout var...setting to 5secs\n")
		tOut = 5000
	}
	ccStartupTimeout := time.Duration(tOut) * time.Millisecond

	pb.RegisterChaincodeSupportServer(grpcServer, chaincode.NewChaincodeSupport(chainname, peer.GetPeerEndpoint, userRunsCC, ccStartupTimeout))
}<commit_msg>Removed unused imports<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

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

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

package obcca

import (
	"testing"
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
	"sync"
	"io/ioutil"
	"encoding/json"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
	"golang.org/x/net/context"
	google_protobuf "google/protobuf"

	"github.com/openblockchain/obc-peer/openchain"
	"github.com/openblockchain/obc-peer/openchain/chaincode"
	"github.com/openblockchain/obc-peer/openchain/consensus/helper"
	"github.com/openblockchain/obc-peer/openchain/ledger/genesis"
	"github.com/openblockchain/obc-peer/openchain/peer"
	"github.com/openblockchain/obc-peer/openchain/rest"
	pb "github.com/openblockchain/obc-peer/protos"
	"github.com/openblockchain/obc-peer/openchain/ledger"
)

var (
	tca *TCA
	eca *ECA
)

type ValidityPeriod struct {
	Name  string
	Value string
}

func TestMain(m *testing.M) {
	setupTestConfig()
	os.Exit(m.Run())
}

func setupTestConfig() {
	viper.AutomaticEnv()
	viper.SetConfigName("obcca_test") // name of config file (without extension)
	viper.AddConfigPath("./")         // path to look for the config file in
	viper.AddConfigPath("./..")       // path to look for the config file in
	err := viper.ReadInConfig()       // Find and read the config file
	if err != nil {                   // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
}

func TestValidityPeriod(t *testing.T) {
	var updateInterval int64
	updateInterval = 37

	// 1. Start TCA and Openchain
	go startServices(t)

	// 2. Obtain the validity period by querying and directly from the ledger
	validityPeriod_A := queryValidityPeriod(t)
	validityPeriodFromLedger_A := getValidityPeriodFromLedger(t)

	// 3. Wait for the validity period to be updated...
	time.Sleep(time.Second * 40)

	// ... and read the values again
	validityPeriod_B := queryValidityPeriod(t)
	validityPeriodFromLedger_B := getValidityPeriodFromLedger(t)

	// 5. Stop TCA and Openchain
	stopServices()

	// 6. Compare the values
	if validityPeriod_A != validityPeriodFromLedger_A {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_A, validityPeriodFromLedger_A)
		t.Fail()
	}

	if validityPeriod_B != validityPeriodFromLedger_B {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_B, validityPeriodFromLedger_B)
		t.Fail()
	}

	if validityPeriod_B - validityPeriod_A != updateInterval {
		t.Logf("Validity period difference must be equal to the update interval. Expected: %s, Actual: %s", updateInterval, validityPeriod_B - validityPeriod_A)
		t.Fail()
	}

	// 7. cleanup tca and openchain folders
	if err := os.RemoveAll(viper.GetString("peer.fileSystemPath")); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", viper.GetString("peer.fileSystemPath"), err)
	}
	if err := os.RemoveAll(".obcca"); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", ".obcca", err)
	}
}

func startServices(t *testing.T) {
	go startTCA()
	err := startOpenchain()
	if(err != nil){
		t.Logf("Error starting Openchain: %s", err)
		t.Fail()
	}
}

func stopServices(){
	stopOpenchain()
	stopTCA()
}

func startTCA() {
	LogInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr, os.Stdout)

	eca = NewECA()
	defer eca.Close()

	tca = NewTCA(eca)
	defer tca.Close()

	var wg sync.WaitGroup
	eca.Start(&wg)
	tca.Start(&wg)

	wg.Wait()
}

func stopTCA(){
	tca.Stop()
	eca.Stop()
}

func queryValidityPeriod(t *testing.T) int64 {
	url := "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update"
	version := "0.0.1"
	args := []string{"system.validity.period"}

	validityPeriod, err := queryTransaction(url, version, args)
	if err != nil {
		t.Logf("Failed querying validity period: %s", err)
		t.Fail()
	}

	var vp ValidityPeriod
	json.Unmarshal(validityPeriod, &vp)

	value, err := strconv.ParseInt(vp.Value, 10, 64)
	if err != nil {
		t.Logf("Failed parsing validity period: %s", err)
		t.Fail()
	}

	return value
}

func getValidityPeriodFromLedger(t *testing.T) int64 {
	chaincodeID := &pb.ChaincodeID{Url: "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update",
		Version: "0.0.1",
	}

	cid, _ := getChaincodeID(chaincodeID)

	ledger, err := ledger.GetLedger()
	if err != nil {
		t.Logf("Failed getting access to the ledger: %s", err)
		t.Fail()
	}

	vp_bytes, err := ledger.GetState(cid, "system.validity.period", true)
	if err != nil {
		t.Logf("Failed reading validity period from the ledger: %s", err)
		t.Fail()
	}

	i, err := strconv.ParseInt(string(vp_bytes[:]), 10, 64)
	if err != nil {
		t.Logf("Failed to parse validity period: %s", err)
		t.Fail()
	}

	return i
 }

// getChaincodeID constructs the ID from pb.ChaincodeID; used by handlerMap
func getChaincodeID(cID *pb.ChaincodeID) (string, error) {
	if cID == nil {
		return "", fmt.Errorf("Cannot construct chaincodeID, got nil object")
	}
	var urlLocation string
	if strings.HasPrefix(cID.Url, "http://") {
		urlLocation = cID.Url[7:]
	} else if strings.HasPrefix(cID.Url, "https://") {
		urlLocation = cID.Url[8:]
	} else {
		urlLocation = cID.Url
	}
	return urlLocation + ":" + cID.Version, nil
}

func queryTransaction(url string, version string, args []string) ([]byte, error) {

	chaincodeInvocationSpec := createChaincodeInvocationForQuery(args, url, version, "system_chaincode_invoker")

	fmt.Printf("Going to query\n")

	response, err := queryChaincode(chaincodeInvocationSpec)

	if err != nil {
		return nil, fmt.Errorf("Error querying <%s>: %s", url, err)
	}

	logger.Info("Successfully invoked validity period update: %s(%s)", url, string(response.Msg))

	return response.Msg, nil
}

func queryChaincode(chaincodeInvSpec *pb.ChaincodeInvocationSpec) (*pb.Response, error) {

	devopsClient, err := getDevopsClient(viper.GetString("pki.validity-period.devops-address"))
	if err != nil {
		logger.Error(fmt.Sprintf("Error retrieving devops client: %s", err))
		return nil,err
	}

	resp, err := devopsClient.Query(context.Background(), chaincodeInvSpec)

	if err != nil {
		logger.Error(fmt.Sprintf("Error invoking validity period update system chaincode: %s", err))
		return nil,err
	}

	logger.Info("Successfully invoked validity period update: %s(%s)", chaincodeInvSpec, string(resp.Msg))

	return resp,nil
}

func createChaincodeInvocationForQuery(arguments []string, chaincodePath string, chaincodeVersion string, token string) *pb.ChaincodeInvocationSpec {
	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
		ChaincodeID: &pb.ChaincodeID{Url: chaincodePath,
			Version: chaincodeVersion,
		},
		CtorMsg: &pb.ChaincodeInput{Function: "query",
			Args: arguments,
		},
	}

	spec.SecureContext = string(token)

	invocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}

	return invocationSpec
}

func startOpenchain() error {

	peerEndpoint, err := peer.GetPeerEndpoint()
	if err != nil {
		logger.Error(fmt.Sprintf("Failed to get Peer Endpoint: %s", err))
		return err
	}

	listenAddr := viper.GetString("peer.listenaddress")

	if "" == listenAddr {
		logger.Debug("Listen address not specified, using peer endpoint address")
		listenAddr = peerEndpoint.Address
	}

	lis, err := net.Listen("tcp", listenAddr)
	if err != nil {
		grpclog.Fatalf("failed to listen: %v", err)
	}

//	ehubLis, ehubGrpcServer, err := createEventHubServer()
//	if err != nil {
//		grpclog.Fatalf("failed to create ehub server: %v", err)
//	}

	logger.Info("Security enabled status: %t", viper.GetBool("security.enabled"))

	var opts []grpc.ServerOption
	if viper.GetBool("peer.tls.enabled") {
		creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"), viper.GetString("peer.tls.key.file"))
		if err != nil {
			grpclog.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}

	grpcServer := grpc.NewServer(opts...)

	// Register the Peer server
	//pb.RegisterPeerServer(grpcServer, openchain.NewPeer())
	var peerServer *peer.PeerImpl

	if viper.GetBool("peer.validator.enabled") {
		logger.Debug("Running as validating peer - installing consensus %s", viper.GetString("peer.validator.consensus"))
		peerServer, _ = peer.NewPeerWithHandler(helper.NewConsensusHandler)
	} else {
		logger.Debug("Running as non-validating peer")
		peerServer, _ = peer.NewPeerWithHandler(peer.NewPeerHandler)
	}
	pb.RegisterPeerServer(grpcServer, peerServer)

	// Register the Admin server
	pb.RegisterAdminServer(grpcServer, openchain.NewAdminServer())

	// Register ChaincodeSupport server...
	// TODO : not the "DefaultChain" ... we have to revisit when we do multichain
	registerChaincodeSupport(chaincode.DefaultChain, grpcServer)

	// Register Devops server
	serverDevops := openchain.NewDevopsServer(peerServer)
	pb.RegisterDevopsServer(grpcServer, serverDevops)

	// Register the ServerOpenchain server
	serverOpenchain, err := openchain.NewOpenchainServer()
	if err != nil {
		logger.Error(fmt.Sprintf("Error creating OpenchainServer: %s", err))
		return err
	}

	pb.RegisterOpenchainServer(grpcServer, serverOpenchain)

	// Create and register the REST service
	go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)

	rootNode, err := openchain.GetRootNode()
	if err != nil {
		grpclog.Fatalf("Failed to get peer.discovery.rootnode valey: %s", err)
	}

	logger.Info("Starting peer with id=%s, network id=%s, address=%s, discovery.rootnode=%s, validator=%v",
		peerEndpoint.ID, viper.GetString("peer.networkId"),
		peerEndpoint.Address, rootNode, viper.GetBool("peer.validator.enabled"))

	// Start the grpc server. Done in a goroutine so we can deploy the
	// genesis block if needed.
	serve := make(chan bool)
	go func() {
		grpcServer.Serve(lis)
		serve <- true
	}()

	// Deploy the geneis block if needed.
	if viper.GetBool("peer.validator.enabled") {
		makeGeneisError := genesis.MakeGenesis(peerServer.GetSecHelper())
		if makeGeneisError != nil {
			return makeGeneisError
		}
	}

	//start the event hub server
//	if ehubGrpcServer != nil && ehubLis != nil {
//		go ehubGrpcServer.Serve(ehubLis)
//	}

	// Block until grpc server exits
	<-serve

	return nil
}

func stopOpenchain() {
	clientConn, err := peer.NewPeerClientConnection()
	if err != nil {
		logger.Error("Error trying to connect to local peer:", err)
		return
	}

	logger.Info("Stopping peer...")
	serverClient := pb.NewAdminClient(clientConn)

	status, err := serverClient.StopServer(context.Background(), &google_protobuf.Empty{})
	logger.Info("Current status: %s", status)

}

func registerChaincodeSupport(chainname chaincode.ChainName, grpcServer *grpc.Server) {
	//get user mode
	userRunsCC := false
	if viper.GetString("chaincode.mode") == chaincode.DevModeUserRunsChaincode {
		userRunsCC = true
	}

	//get chaincode startup timeout
	tOut, err := strconv.Atoi(viper.GetString("chaincode.startuptimeout"))
	if err != nil { //what went wrong ?
		fmt.Printf("could not retrive timeout var...setting to 5secs\n")
		tOut = 5000
	}
	ccStartupTimeout := time.Duration(tOut) * time.Millisecond

	pb.RegisterChaincodeSupportServer(grpcServer, chaincode.NewChaincodeSupport(chainname, peer.GetPeerEndpoint, userRunsCC, ccStartupTimeout))
}<|endoftext|>


<commit_before>package page_runner

import (
	"fmt"
	"github.com/jesusslim/slimmysql"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

type PageRunner struct {
	id        string
	waitGroup sync.WaitGroup
	sql       *slimmysql.Sql
	path      string    //扫描路径
	suffix    string    //文件后缀
	baseUrl   string    //http基础url
	ignore    []string  //忽略的目录/文件名
	rep       []string  //需替换为空的字符串
	extError  []string  //其他错误标示
	c         chan bool //channel 建议根据服务器情况调整合适大小
	result    map[string]map[string]interface{}
	cookie    string //cookie for sessionid
	maxTimes  int    //最大尝试访问次数
}

func NewPageRunner(id string, path string, suffix string, baseUrl string, ignore []string, rep []string, extErr []string, sql *slimmysql.Sql, channelLength int, cookie string, maxTimes int) *PageRunner {
	if !strings.HasSuffix(baseUrl, "/") {
		baseUrl = baseUrl + "/"
	}
	if suffix == "" {
		suffix = "index.html"
	}
	if channelLength == 0 {
		channelLength = 1
	}
	if maxTimes == 0 {
		maxTimes = 20
	}
	return &PageRunner{
		sql:      sql,
		path:     path,
		suffix:   suffix,
		baseUrl:  baseUrl,
		ignore:   ignore,
		extError: extErr,
		rep:      rep,
		c:        make(chan bool, channelLength),
		result:   make(map[string]map[string]interface{}),
		cookie:   cookie,
		maxTimes: maxTimes,
	}
}

//for thinkphp
func NewPageRunnerTP(id string, path, baseUrl string, rp []string, extErr []string, sql *slimmysql.Sql, channelLength int, cookie string, maxTimes int) *PageRunner {
	return NewPageRunner(
		id,
		path,
		".html",
		baseUrl,
		[]string{
			"Widget",
		},
		append(rp, "View/index.html", "View/"),
		extErr,
		sql,
		channelLength,
		cookie,
		maxTimes)
}

type UrlModel struct {
	module     string
	controller string
	action     string
	url        string
	times      int
	lastErr    string
}

func NewUrlModel(baseUrl, subUrl string) *UrlModel {
	mdl := &UrlModel{
		url:   baseUrl + subUrl,
		times: 0,
	}
	subs := strings.Split(subUrl, "/")
	l := len(subs)
	if l > 0 {
		mdl.module = subs[0]
	}
	if l > 1 {
		mdl.controller = subs[1]
	}
	if l > 2 {
		mdl.action = subs[2]
	}
	return mdl
}

func (this *PageRunner) fetchUrl(id string, url *UrlModel) {
	this.c <- true
	var start time.Time
	var err error
	var resp *http.Response
	if this.cookie == "" {
		//1.easy
		start = time.Now()
		resp, err = http.Get(url.url)
	} else {
		//2.with cookie
		client := &http.Client{}
		req, _ := http.NewRequest("GET", url.url, nil)
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Set("Cookie", this.cookie)
		start := time.Now()
		resp, err = client.Do(req)
	}
	duration := time.Since(start).Seconds() * 1000
	if err != nil {
		<-this.c
		fmt.Println("ERROR:" + err.Error())
		if url.times == this.maxTimes-1 {
			//结束 give up
			this.result[id] = map[string]interface{}{
				"duration":    0,
				"url":         url.url,
				"status":      -1,
				"create_time": time.Now().Unix(),
				"same":        0,
				"task_id":     this.id,
				"is_err":      1,
				"err":         url.lastErr,
				"module":      url.module,
				"controller":  url.controller,
				"action":      url.action,
				"times":       url.times + 1,
			}
			this.waitGroup.Done()
		} else {
			url.times++
			url.lastErr = err.Error()
			this.fetchUrl(id, url)
		}
	} else {
		defer resp.Body.Close()

		_, ok := this.result[id]

		if !ok {
			status := resp.StatusCode
			create_time := time.Now().Unix()
			header := resp.Header
			last_url := resp.Request.URL.String()
			same := 0
			is_err := 0
			if status != 200 {
				is_err = 1
			}
			if strings.EqualFold(url.url, last_url) {
				same = 1
			}
			// fmt.Println(header.Get("Date"))
			server := header.Get("Server")
			//xby := header.Get("X-Powered-By")
			if same == 0 {
				for _, e := range this.extError {
					if strings.Contains(last_url, e) {
						is_err = 1
						break
					}
				}
			}

			this.result[id] = map[string]interface{}{
				"duration":    int(duration),
				"url":         url.url,
				"status":      status,
				"create_time": create_time,
				"server":      server,
				"last_url":    last_url,
				"same":        same,
				"task_id":     this.id,
				"is_err":      is_err,
				"module":      url.module,
				"controller":  url.controller,
				"action":      url.action,
				"err":         url.lastErr,
				"times":       url.times + 1,
			}
		}

		<-this.c
		this.waitGroup.Done()
	}
}

func (this *PageRunner) walkDir() (map[string]*UrlModel, error) {
	files := map[string]*UrlModel{}
	suffix := strings.ToUpper(this.suffix)
	id := 0
	err := filepath.Walk(this.path, func(filename string, info os.FileInfo, err_inside error) error {
		if info.IsDir() {
			return nil
		}
		if strings.HasSuffix(strings.ToUpper(info.Name()), suffix) {
			for _, ig := range this.ignore {
				if strings.Contains(filename, ig) {
					return nil
				}
			}
			for _, rp := range this.rep {
				filename = strings.Replace(filename, rp, "", -1)
			}
			if strings.HasPrefix(filename, "/") {
				filename = filename[1:]
			}
			files[strconv.Itoa(id)] = NewUrlModel(this.baseUrl, filename)
			id++
		}
		return nil
	})
	return files, err
}

func (this *PageRunner) Run() {
	urls, err := this.walkDir()
	if err != nil {
		fmt.Println("ERROR:", err.Error())
	} else {
		num := len(urls)
		id, _ := this.sql.Table("task").Add(map[string]interface{}{
			"num":         num,
			"title":       "Test",
			"create_time": time.Now().Unix(),
		})
		this.id = string(strconv.FormatInt(id, 10))
		for k, v := range urls {
			this.waitGroup.Add(1)
			go this.fetchUrl(k, v)
		}
		this.waitGroup.Wait()
		fmt.Println("DataOk")
		success := len(this.result)
		this.sql.Clear().Table("task").Where("id = "+this.id).SetInc("success", success)
		this.sql = this.sql.Clear()
		for _, v := range this.result {
			this.sql.Table("url").Add(v)
		}
		fmt.Println("Finished")

	}
}

//example
// func main() {
// 	slimmysql.RegisterConnectionDefault(false, "127.0.0.1", "3307", "test", "root", "root", "", false)
// 	sql, _ := slimmysql.NewSqlInstanceDefault()
// 	baseUrl := "http://localhost:8888/teenager/Student"
// 	path := "/Applications/MAMP/htdocs/teenager/Application/Student"
// 	extErr := []string{
// 		"404",
// 		"error",
// 	}
// 	runner := NewPageRunnerTP("0", path, baseUrl,[]string{"/Applications/MAMP/htdocs/teenager/Application/"}, extErr, sql, 30, "PHPSESSID=c3146dcc95ba4e5992441718296aef1d", 50)
// 	runner.Run()
// }
<commit_msg>fix bug<commit_after>package page_runner

import (
	"fmt"
	"github.com/jesusslim/slimmysql"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

type PageRunner struct {
	id        string
	waitGroup sync.WaitGroup
	sql       *slimmysql.Sql
	path      string    //扫描路径
	suffix    string    //文件后缀
	baseUrl   string    //http基础url
	ignore    []string  //忽略的目录/文件名
	rep       []string  //需替换为空的字符串
	extError  []string  //其他错误标示
	c         chan bool //channel 建议根据服务器情况调整合适大小
	result    map[string]map[string]interface{}
	cookie    string //cookie for sessionid
	maxTimes  int    //最大尝试访问次数
}

func NewPageRunner(id string, path string, suffix string, baseUrl string, ignore []string, rep []string, extErr []string, sql *slimmysql.Sql, channelLength int, cookie string, maxTimes int) *PageRunner {
	if !strings.HasSuffix(baseUrl, "/") {
		baseUrl = baseUrl + "/"
	}
	if suffix == "" {
		suffix = "index.html"
	}
	if channelLength == 0 {
		channelLength = 1
	}
	if maxTimes == 0 {
		maxTimes = 20
	}
	return &PageRunner{
		sql:      sql,
		path:     path,
		suffix:   suffix,
		baseUrl:  baseUrl,
		ignore:   ignore,
		extError: extErr,
		rep:      rep,
		c:        make(chan bool, channelLength),
		result:   make(map[string]map[string]interface{}),
		cookie:   cookie,
		maxTimes: maxTimes,
	}
}

//for thinkphp
func NewPageRunnerTP(id string, path, baseUrl string, rp []string, extErr []string, sql *slimmysql.Sql, channelLength int, cookie string, maxTimes int) *PageRunner {
	return NewPageRunner(
		id,
		path,
		".html",
		baseUrl,
		[]string{
			"Widget",
		},
		append(rp, "View/index.html", "View/"),
		extErr,
		sql,
		channelLength,
		cookie,
		maxTimes)
}

type UrlModel struct {
	module     string
	controller string
	action     string
	url        string
	times      int
	lastErr    string
}

func NewUrlModel(baseUrl, subUrl string) *UrlModel {
	mdl := &UrlModel{
		url:   baseUrl + subUrl,
		times: 0,
	}
	subs := strings.Split(subUrl, "/")
	l := len(subs)
	if l > 0 {
		mdl.module = subs[0]
	}
	if l > 1 {
		mdl.controller = subs[1]
	}
	if l > 2 {
		mdl.action = subs[2]
	}
	return mdl
}

func (this *PageRunner) fetchUrl(id string, url *UrlModel) {
	this.c <- true
	var start time.Time
	var err error
	var resp *http.Response
	if this.cookie == "" {
		//1.easy
		start = time.Now()
		resp, err = http.Get(url.url)
	} else {
		//2.with cookie
		client := &http.Client{}
		req, _ := http.NewRequest("GET", url.url, nil)
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Set("Cookie", this.cookie)
		start = time.Now()
		resp, err = client.Do(req)
	}
	duration := time.Since(start).Seconds() * 1000
	if err != nil {
		<-this.c
		fmt.Println("ERROR:" + err.Error())
		if url.times == this.maxTimes-1 {
			//结束 give up
			this.result[id] = map[string]interface{}{
				"duration":    0,
				"url":         url.url,
				"status":      -1,
				"create_time": time.Now().Unix(),
				"same":        0,
				"task_id":     this.id,
				"is_err":      1,
				"err":         url.lastErr,
				"module":      url.module,
				"controller":  url.controller,
				"action":      url.action,
				"times":       url.times + 1,
			}
			this.waitGroup.Done()
		} else {
			url.times++
			url.lastErr = err.Error()
			this.fetchUrl(id, url)
		}
	} else {
		defer resp.Body.Close()

		_, ok := this.result[id]

		if !ok {
			status := resp.StatusCode
			create_time := time.Now().Unix()
			header := resp.Header
			last_url := resp.Request.URL.String()
			same := 0
			is_err := 0
			if status != 200 {
				is_err = 1
			}
			if strings.EqualFold(url.url, last_url) {
				same = 1
			}
			// fmt.Println(header.Get("Date"))
			server := header.Get("Server")
			//xby := header.Get("X-Powered-By")
			if same == 0 {
				for _, e := range this.extError {
					if strings.Contains(last_url, e) {
						is_err = 1
						break
					}
				}
			}

			this.result[id] = map[string]interface{}{
				"duration":    int(duration),
				"url":         url.url,
				"status":      status,
				"create_time": create_time,
				"server":      server,
				"last_url":    last_url,
				"same":        same,
				"task_id":     this.id,
				"is_err":      is_err,
				"module":      url.module,
				"controller":  url.controller,
				"action":      url.action,
				"err":         url.lastErr,
				"times":       url.times + 1,
			}
		}

		<-this.c
		this.waitGroup.Done()
	}
}

func (this *PageRunner) walkDir() (map[string]*UrlModel, error) {
	files := map[string]*UrlModel{}
	suffix := strings.ToUpper(this.suffix)
	id := 0
	err := filepath.Walk(this.path, func(filename string, info os.FileInfo, err_inside error) error {
		if info.IsDir() {
			return nil
		}
		if strings.HasSuffix(strings.ToUpper(info.Name()), suffix) {
			for _, ig := range this.ignore {
				if strings.Contains(filename, ig) {
					return nil
				}
			}
			for _, rp := range this.rep {
				filename = strings.Replace(filename, rp, "", -1)
			}
			if strings.HasPrefix(filename, "/") {
				filename = filename[1:]
			}
			files[strconv.Itoa(id)] = NewUrlModel(this.baseUrl, filename)
			id++
		}
		return nil
	})
	return files, err
}

func (this *PageRunner) Run() {
	urls, err := this.walkDir()
	if err != nil {
		fmt.Println("ERROR:", err.Error())
	} else {
		num := len(urls)
		id, _ := this.sql.Table("task").Add(map[string]interface{}{
			"num":         num,
			"title":       "Test",
			"create_time": time.Now().Unix(),
		})
		this.id = string(strconv.FormatInt(id, 10))
		for k, v := range urls {
			this.waitGroup.Add(1)
			go this.fetchUrl(k, v)
		}
		this.waitGroup.Wait()
		fmt.Println("DataOk")
		success := len(this.result)
		this.sql.Clear().Table("task").Where("id = "+this.id).SetInc("success", success)
		this.sql = this.sql.Clear()
		for _, v := range this.result {
			this.sql.Table("url").Add(v)
		}
		fmt.Println("Finished")

	}
}

//example
// func main() {
// 	slimmysql.RegisterConnectionDefault(false, "127.0.0.1", "3307", "test", "root", "root", "", false)
// 	sql, _ := slimmysql.NewSqlInstanceDefault()
// 	baseUrl := "http://localhost:8888/teenager/Student"
// 	path := "/Applications/MAMP/htdocs/teenager/Application/Student"
// 	extErr := []string{
// 		"404",
// 		"error",
// 	}
// 	runner := NewPageRunnerTP("0", path, baseUrl,[]string{"/Applications/MAMP/htdocs/teenager/Application/"}, extErr, sql, 30, "PHPSESSID=c3146dcc95ba4e5992441718296aef1d", 50)
// 	runner.Run()
// }
<|endoftext|>


<commit_before>package personal

import (
	"common"
	"encoding/json"

	"appengine"
	"appengine/urlfetch"

	"bytes"
	"fmt"

	"io/ioutil"
	"net/http"
)

func LastTweetActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) (pActivesList *ActivesList) {
	go TweetActiveList(cxt, session, access_token, user, page, showMe, ch)
	pActivesList = <-ch
	atMoment := pActivesList.Notice.ReferCount
	if atMoment > 0 { //Only last new referes will be shown on client.
		pActivesList.ActivesArray = pActivesList.ActivesArray[:(atMoment)]
	} else {
		pActivesList = nil
	}
	return
}

func LastCommentActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) (pActivesList *ActivesList) {
	go CommentsActiveList(cxt, session, access_token, user, page, showMe, ch)
	pActivesList = <-ch
	atMoment := pActivesList.Notice.ReplyCount
	if atMoment > 0 { //Only last new replies will be shown on client.
		pActivesList.ActivesArray = pActivesList.ActivesArray[:(atMoment)]
	} else {
		pActivesList = nil
	}
	return
}

func TweetActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) {
	Actives(cxt, session, access_token, user, 2, page, showMe, ch)
}

func CommentsActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) {
	Actives(cxt, session, access_token, user, 3, page, showMe, ch)
}

func Actives(cxt appengine.Context, session string, access_token string, user int, catalog int, page int, showMe bool, ch chan *ActivesList) {
	client := urlfetch.Client(cxt)
	body := fmt.Sprintf(common.ACTIVE_LIST_SCHEME, catalog, user, page, access_token)
	if r, e := http.NewRequest(common.POST, common.ACTIVE_LIST_URL, bytes.NewBufferString(body)); e == nil {
		common.MakeHeader(r, "oscid="+session, 0)
		if resp, e := client.Do(r); e == nil {
			if resp != nil {
				defer resp.Body.Close()
			}
			pActivesList := new(ActivesList)    //Only for temp .
			pActivesListRet := new(ActivesList) //Real to return.
			if bytes, e := ioutil.ReadAll(resp.Body); e == nil {
				if err := json.Unmarshal(bytes, pActivesList); err == nil {
					if !showMe {
						pActivesListRet.Notice = pActivesList.Notice
						pActivesListRet.ActivesArray = []Active{}
						for _, v := range pActivesList.ActivesArray {
							if v.AuthorId != user {
								pActivesListRet.ActivesArray = append(pActivesListRet.ActivesArray, v)
							}
						}
					} else {
						pActivesListRet = pActivesList
					}
					ch <- pActivesListRet
				} else {
					panic(e)
				}
			} else {
				panic(e)
			}
		} else {
			panic(e)
		}
	} else {
		panic(e)
	}
}
<commit_msg>Bugfix. Diff the discard filtered notices.<commit_after>package personal

import (
	"common"
	"encoding/json"

	"appengine"
	"appengine/urlfetch"

	"bytes"
	"fmt"

	"io/ioutil"
	"net/http"
)

func LastTweetActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) (pActivesList *ActivesList) {
	go TweetActiveList(cxt, session, access_token, user, page, showMe, ch)
	pActivesList = <-ch
	atMoment := pActivesList.Notice.ReferCount
	diff := pActivesList.Notice.ReferCount - len(pActivesList.ActivesArray)
	atMoment -= diff
	if atMoment > 0 { //Only last new referes will be shown on client.
		pActivesList.ActivesArray = pActivesList.ActivesArray[:(atMoment)]
	} else {
		pActivesList = nil
	}
	return
}

func LastCommentActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) (pActivesList *ActivesList) {
	go CommentsActiveList(cxt, session, access_token, user, page, showMe, ch)
	pActivesList = <-ch
	atMoment := pActivesList.Notice.ReplyCount
	diff := pActivesList.Notice.ReplyCount - len(pActivesList.ActivesArray)
	atMoment -= diff
	if atMoment > 0 { //Only last new replies will be shown on client.
		pActivesList.ActivesArray = pActivesList.ActivesArray[:(atMoment)]
	} else {
		pActivesList = nil
	}
	return
}

func TweetActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) {
	Actives(cxt, session, access_token, user, 2, page, showMe, ch)
}

func CommentsActiveList(cxt appengine.Context, session string, access_token string, user int, page int, showMe bool, ch chan *ActivesList) {
	Actives(cxt, session, access_token, user, 3, page, showMe, ch)
}

func Actives(cxt appengine.Context, session string, access_token string, user int, catalog int, page int, showMe bool, ch chan *ActivesList) {
	client := urlfetch.Client(cxt)
	body := fmt.Sprintf(common.ACTIVE_LIST_SCHEME, catalog, user, page, access_token)
	if r, e := http.NewRequest(common.POST, common.ACTIVE_LIST_URL, bytes.NewBufferString(body)); e == nil {
		common.MakeHeader(r, "oscid="+session, 0)
		if resp, e := client.Do(r); e == nil {
			if resp != nil {
				defer resp.Body.Close()
			}
			pActivesList := new(ActivesList)    //Only for temp .
			pActivesListRet := new(ActivesList) //Real to return.
			if bytes, e := ioutil.ReadAll(resp.Body); e == nil {
				if err := json.Unmarshal(bytes, pActivesList); err == nil {
					if !showMe {
						pActivesListRet.Notice = pActivesList.Notice
						pActivesListRet.ActivesArray = []Active{}
						for _, v := range pActivesList.ActivesArray {
							if v.AuthorId != user {
								pActivesListRet.ActivesArray = append(pActivesListRet.ActivesArray, v)
							}
						}
					} else {
						pActivesListRet = pActivesList
					}
					ch <- pActivesListRet
				} else {
					panic(e)
				}
			} else {
				panic(e)
			}
		} else {
			panic(e)
		}
	} else {
		panic(e)
	}
}
<|endoftext|>


<commit_before>package mario

import (
	"fmt"
	neural "github.com/poseidon4o/go-neural/src/neural"
	util "github.com/poseidon4o/go-neural/src/util"
	"math"
	"sort"
)

type NeuronName int

const (
	posX      NeuronName = iota
	posY      NeuronName = iota
	velY      NeuronName = iota
	velX      NeuronName = iota
	H1        NeuronName = iota
	H2        NeuronName = iota
	H3        NeuronName = iota
	H4        NeuronName = iota
	H5        NeuronName = iota
	H6        NeuronName = iota
	H7        NeuronName = iota
	H8        NeuronName = iota
	R1        NeuronName = iota
	R2        NeuronName = iota
	R3        NeuronName = iota
	R4        NeuronName = iota
	R5        NeuronName = iota
	R6        NeuronName = iota
	R7        NeuronName = iota
	R8        NeuronName = iota
	jump      NeuronName = iota
	xMove     NeuronName = iota
	NRN_COUNT int        = iota
)

func nrn(name NeuronName) int {
	return int(name)
}

type MarioNode struct {
	fig        *Figure
	brain      *neural.Net
	bestX      float64
	dead       bool
	idleFrames uint32
}

type MarioCol []MarioNode

func (figs MarioCol) Len() int {
	return len(figs)
}

func (figs MarioCol) Less(c, r int) bool {
	return figs[c].bestX > figs[r].bestX
}

func (figs MarioCol) Swap(c, r int) {
	figs[c], figs[r] = figs[r], figs[c]
}

type Mario struct {
	figures  MarioCol
	lvl      Level
	drawCb   func(pos, size *util.Vector, color uint32)
	drawSize int
}

func (m *Mario) Complete() float64 {
	return m.figures[0].bestX / m.lvl.size.X
}

func (m *Mario) Done() bool {
	return false
}

func (m *Mario) SetDrawRectCb(cb func(pos, size *util.Vector, color uint32)) {
	m.drawCb = cb
}

func (m *Mario) LogicTick(dt float64) {
	m.lvl.Step(dt)
	m.checkStep()
	m.mutateStep()
	if len(m.figures) > 1 {
		m.thnikStep()
	}
}

func (m *Mario) Jump() {
	m.figures[0].fig.Jump()
}

func (m *Mario) Move(dir int) {
	m.figures[0].fig.Move(dir)
}

func (m *Mario) Figs() MarioCol {
	return m.figures
}

func NewMario(figCount int, size *util.Vector) *Mario {
	fmt.Println("")
	level := NewLevel(int(size.X), int(size.Y))
	level.AddFigures(figCount)

	nets := make([]*neural.Net, figCount, figCount)
	for c := range nets {
		nets[c] = neural.NewNet(NRN_COUNT)

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			// input to H
			*nets[c].Synapse(nrn(posX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(posY), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velY), r+nrn(H1)) = 0.0

			// R to output
			*nets[c].Synapse(r+nrn(R1), nrn(jump)) = 0.0
			*nets[c].Synapse(r+nrn(R1), nrn(xMove)) = 0.0
		}

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			for q := 0; q < (nrn(H8) - nrn(H1)); q++ {
				*nets[c].Synapse(r+nrn(H1), q+nrn(R1)) = 0.0
			}
		}

		nets[c].Randomize()
	}

	figs := make(MarioCol, figCount, figCount)
	for c := range figs {
		figs[c].brain = nets[c]
		figs[c].dead = false
		figs[c].bestX = 0
		figs[c].fig = level.figures[c]
	}

	return &Mario{
		figures:  figs,
		lvl:      *level,
		drawCb:   func(pos, size *util.Vector, color uint32) {},
		drawSize: 5,
	}
}

func (m *Mario) DrawTick() {
	var (
		red   = uint32(0xffff0000)
		green = uint32(0xff00ff00)
		blue  = uint32(0xff0000ff)
	)

	blSize := util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE))
	blSizeSmall := blSize.Scale(0.5)

	translate := util.NewVector(6, 6)

	size := util.NewVector(float64(m.drawSize), float64(m.drawSize))

	for c := range m.lvl.blocks {
		for r := range m.lvl.blocks[c] {
			if m.lvl.blocks[c][r] != nil {
				m.drawCb(m.lvl.blocks[c][r], blSize, red)
				m.drawCb(m.lvl.blocks[c][r].Add(translate), blSizeSmall, green)
			}
		}
	}

	for c := range m.figures {
		m.drawCb(m.figures[c].fig.pos.Add(size.Scale(0.5).Neg()), size, blue)
	}
}

func (m *Mario) checkStep() {
	for c := range m.figures {
		fig := m.figures[c].fig

		if fig.nextPos.Y > m.lvl.size.Y || fig.nextPos.Y < 0 {
			m.figures[c].dead = true
			continue
		}

		if fig.nextPos.X < 0 {
			fig.nextPos.X = 0
		} else if fig.nextPos.X > m.lvl.size.X {
			fig.nextPos.X = m.lvl.size.X
		}

		block := m.lvl.FloorAt(&fig.pos)

		if block == nil || fig.nextPos.Y < block.Y {
			fig.pos.Y = fig.nextPos.Y
		} else {
			// m.drawCb(block, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
			// land on block
			fig.vel.Y = 0
			fig.pos.Y = block.Y - 0.1
			fig.Land()
		}

		if fig.pos.X != fig.nextPos.X {
			fig.nextPos.Y = fig.pos.Y
			colide := m.lvl.CubeAt(&fig.nextPos)
			if colide != nil {
				// m.drawCb(colide, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
				if fig.pos.X < fig.nextPos.X {
					// collide right
					fig.pos.X = colide.X - 0.1
				} else {
					// colide left
					fig.pos.X = colide.X + float64(BLOCK_SIZE) + 0.1
				}
			} else {
				fig.pos.X = fig.nextPos.X
			}
		}
	}
}

func (m *Mario) thnikStep() {
	wg := make(chan struct{}, len(m.figures))

	thinkBird := func(c int) {
		m.figures[c].brain.Stimulate(nrn(posX), m.figures[c].fig.pos.X)
		m.figures[c].brain.Stimulate(nrn(posY), m.figures[c].fig.pos.Y)
		m.figures[c].brain.Stimulate(nrn(velX), m.figures[c].fig.vel.X)
		m.figures[c].brain.Stimulate(nrn(velY), m.figures[c].fig.vel.Y)

		m.figures[c].brain.Step()

		if m.figures[c].brain.ValueOf(nrn(jump)) > 0.75 {
			m.figures[c].fig.Jump()
		}

		xMoveValue := m.figures[c].brain.ValueOf(nrn(xMove))
		if math.Abs(xMoveValue) > 0.75 {
			m.figures[c].fig.Move(int(xMoveValue * 10))
		}

		m.figures[c].brain.Clear()
		wg <- struct{}{}
	}

	for c := 0; c < len(m.figures); c++ {
		go thinkBird(c)
	}

	for c := 0; c < len(m.figures); c++ {
		<-wg
	}
}

func (m *Mario) mutateStep() {
	sort.Sort(m.figures)

	randNet := func() *neural.Net {
		return m.figures[int(neural.RandMax(float64(len(m.figures))))].brain
	}

	best := m.figures[0].brain

	var idleThreshold uint32 = 600

	for c := range m.figures {
		if m.figures[c].dead {
			m.figures[c].dead = false
			m.figures[c].fig.pos = *m.lvl.NewFigurePos()
			m.figures[c].fig.vel = *util.NewVector(0, 0)

			if m.figures[c].idleFrames >= idleThreshold {
				m.figures[c].brain.Mutate(0.75)
				m.figures[c].bestX *= 0.25
			} else {
				m.figures[c].brain = neural.Cross(best, randNet())
				if neural.Chance(0.01) {
					// penalize best achievement due to mutation
					m.figures[c].bestX *= 0.8
					m.figures[c].brain.Mutate(0.25)
				}
			}

			m.figures[c].idleFrames = 0

		} else {
			if m.figures[c].fig.pos.X > m.figures[c].bestX {
				m.figures[c].bestX = m.figures[c].fig.pos.X
			} else {
				m.figures[c].idleFrames++
				if m.figures[c].idleFrames >= 600 {
					m.figures[c].dead = true
					c--
				}
			}

		}
	}

}
<commit_msg>Change mutation parent chocie to exp<commit_after>package mario

import (
	"fmt"
	neural "github.com/poseidon4o/go-neural/src/neural"
	util "github.com/poseidon4o/go-neural/src/util"
	"math"
	"math/rand"
	"sort"
)

type NeuronName int

const (
	posX      NeuronName = iota
	posY      NeuronName = iota
	velY      NeuronName = iota
	velX      NeuronName = iota
	H1        NeuronName = iota
	H2        NeuronName = iota
	H3        NeuronName = iota
	H4        NeuronName = iota
	H5        NeuronName = iota
	H6        NeuronName = iota
	H7        NeuronName = iota
	H8        NeuronName = iota
	R1        NeuronName = iota
	R2        NeuronName = iota
	R3        NeuronName = iota
	R4        NeuronName = iota
	R5        NeuronName = iota
	R6        NeuronName = iota
	R7        NeuronName = iota
	R8        NeuronName = iota
	jump      NeuronName = iota
	xMove     NeuronName = iota
	NRN_COUNT int        = iota
)

func nrn(name NeuronName) int {
	return int(name)
}

type MarioNode struct {
	fig        *Figure
	brain      *neural.Net
	bestX      float64
	dead       bool
	idleFrames uint32
}

type MarioCol []MarioNode

func (figs MarioCol) Len() int {
	return len(figs)
}

func (figs MarioCol) Less(c, r int) bool {
	return figs[c].bestX > figs[r].bestX
}

func (figs MarioCol) Swap(c, r int) {
	figs[c], figs[r] = figs[r], figs[c]
}

type Mario struct {
	figures  MarioCol
	lvl      Level
	drawCb   func(pos, size *util.Vector, color uint32)
	drawSize int
}

func (m *Mario) Complete() float64 {
	return m.figures[0].bestX / m.lvl.size.X
}

func (m *Mario) Done() bool {
	return false
}

func (m *Mario) SetDrawRectCb(cb func(pos, size *util.Vector, color uint32)) {
	m.drawCb = cb
}

func (m *Mario) LogicTick(dt float64) {
	m.lvl.Step(dt)
	m.checkStep()
	m.mutateStep()
	if len(m.figures) > 1 {
		m.thnikStep()
	}
}

func (m *Mario) Jump() {
	m.figures[0].fig.Jump()
}

func (m *Mario) Move(dir int) {
	m.figures[0].fig.Move(dir)
}

func (m *Mario) Figs() MarioCol {
	return m.figures
}

func NewMario(figCount int, size *util.Vector) *Mario {
	fmt.Println("")
	level := NewLevel(int(size.X), int(size.Y))
	level.AddFigures(figCount)

	nets := make([]*neural.Net, figCount, figCount)
	for c := range nets {
		nets[c] = neural.NewNet(NRN_COUNT)

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			// input to H
			*nets[c].Synapse(nrn(posX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(posY), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velY), r+nrn(H1)) = 0.0

			// R to output
			*nets[c].Synapse(r+nrn(R1), nrn(jump)) = 0.0
			*nets[c].Synapse(r+nrn(R1), nrn(xMove)) = 0.0
		}

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			for q := 0; q < (nrn(H8) - nrn(H1)); q++ {
				*nets[c].Synapse(r+nrn(H1), q+nrn(R1)) = 0.0
			}
		}

		nets[c].Randomize()
	}

	figs := make(MarioCol, figCount, figCount)
	for c := range figs {
		figs[c].brain = nets[c]
		figs[c].dead = false
		figs[c].bestX = 0
		figs[c].fig = level.figures[c]
	}

	return &Mario{
		figures:  figs,
		lvl:      *level,
		drawCb:   func(pos, size *util.Vector, color uint32) {},
		drawSize: 5,
	}
}

func (m *Mario) DrawTick() {
	var (
		red   = uint32(0xffff0000)
		green = uint32(0xff00ff00)
		blue  = uint32(0xff0000ff)
	)

	blSize := util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE))
	blSizeSmall := blSize.Scale(0.5)

	translate := util.NewVector(6, 6)

	size := util.NewVector(float64(m.drawSize), float64(m.drawSize))

	for c := range m.lvl.blocks {
		for r := range m.lvl.blocks[c] {
			if m.lvl.blocks[c][r] != nil {
				m.drawCb(m.lvl.blocks[c][r], blSize, red)
				m.drawCb(m.lvl.blocks[c][r].Add(translate), blSizeSmall, green)
			}
		}
	}

	for c := range m.figures {
		m.drawCb(m.figures[c].fig.pos.Add(size.Scale(0.5).Neg()), size, blue)
	}
}

func (m *Mario) checkStep() {
	for c := range m.figures {
		fig := m.figures[c].fig

		if fig.nextPos.Y > m.lvl.size.Y || fig.nextPos.Y < 0 {
			m.figures[c].dead = true
			continue
		}

		if fig.nextPos.X < 0 {
			fig.nextPos.X = 0
		} else if fig.nextPos.X > m.lvl.size.X {
			fig.nextPos.X = m.lvl.size.X
		}

		block := m.lvl.FloorAt(&fig.pos)

		if block == nil || fig.nextPos.Y < block.Y {
			fig.pos.Y = fig.nextPos.Y
		} else {
			// m.drawCb(block, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
			// land on block
			fig.vel.Y = 0
			fig.pos.Y = block.Y - 0.1
			fig.Land()
		}

		if fig.pos.X != fig.nextPos.X {
			fig.nextPos.Y = fig.pos.Y
			colide := m.lvl.CubeAt(&fig.nextPos)
			if colide != nil {
				// m.drawCb(colide, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
				if fig.pos.X < fig.nextPos.X {
					// collide right
					fig.pos.X = colide.X - 0.1
				} else {
					// colide left
					fig.pos.X = colide.X + float64(BLOCK_SIZE) + 0.1
				}
			} else {
				fig.pos.X = fig.nextPos.X
			}
		}
	}
}

func (m *Mario) thnikStep() {
	wg := make(chan struct{}, len(m.figures))

	thinkBird := func(c int) {
		m.figures[c].brain.Stimulate(nrn(posX), m.figures[c].fig.pos.X)
		m.figures[c].brain.Stimulate(nrn(posY), m.figures[c].fig.pos.Y)
		m.figures[c].brain.Stimulate(nrn(velX), m.figures[c].fig.vel.X)
		m.figures[c].brain.Stimulate(nrn(velY), m.figures[c].fig.vel.Y)

		m.figures[c].brain.Step()

		if m.figures[c].brain.ValueOf(nrn(jump)) > 0.75 {
			m.figures[c].fig.Jump()
		}

		xMoveValue := m.figures[c].brain.ValueOf(nrn(xMove))
		if math.Abs(xMoveValue) > 0.75 {
			m.figures[c].fig.Move(int(xMoveValue * 10))
		}

		m.figures[c].brain.Clear()
		wg <- struct{}{}
	}

	for c := 0; c < len(m.figures); c++ {
		go thinkBird(c)
	}

	for c := 0; c < len(m.figures); c++ {
		<-wg
	}
}

func (m *Mario) mutateStep() {
	sort.Sort(m.figures)

	cutOff := 6.0
	randNet := func() *neural.Net {
		idx := 0
		for {
			r := rand.ExpFloat64()
			if r <= cutOff {
				idx = int((r * float64(len(m.figures))) / cutOff)
				break
			}
		}
		return m.figures[idx].brain
	}

	best := m.figures[0].brain

	var idleThreshold uint32 = 600

	for c := range m.figures {
		if m.figures[c].dead {
			m.figures[c].dead = false
			m.figures[c].fig.pos = *m.lvl.NewFigurePos()
			m.figures[c].fig.vel = *util.NewVector(0, 0)

			if m.figures[c].idleFrames >= idleThreshold {
				m.figures[c].brain.Mutate(0.75)
				m.figures[c].bestX *= 0.25
			} else {
				m.figures[c].brain = neural.Cross(best, randNet())
				if neural.Chance(0.01) {
					// penalize best achievement due to mutation
					m.figures[c].bestX *= 0.8
					m.figures[c].brain.Mutate(0.25)
				}
			}

			m.figures[c].idleFrames = 0

		} else {
			if m.figures[c].fig.pos.X > m.figures[c].bestX {
				m.figures[c].bestX = m.figures[c].fig.pos.X
			} else {
				m.figures[c].idleFrames++
				if m.figures[c].idleFrames >= 600 {
					m.figures[c].dead = true
					c--
				}
			}

		}
	}

}
<|endoftext|>


<commit_before>// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package helmhub

import (
	"errors"
	"github.com/goharbor/harbor/src/common/utils/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/model"
)

func init() {
	if err := adp.RegisterFactory(model.RegistryTypeHelmHub, new(factory)); err != nil {
		log.Errorf("failed to register factory for %s: %v", model.RegistryTypeHelmHub, err)
		return
	}
	log.Infof("the factory for adapter %s registered", model.RegistryTypeHelmHub)
}

type factory struct {
}

// Create ...
func (f *factory) Create(r *model.Registry) (adp.Adapter, error) {
	return newAdapter(r)
}

// AdapterPattern ...
func (f *factory) AdapterPattern() *model.AdapterPattern {
	return nil
}

type adapter struct {
	registry *model.Registry
	client   *Client
}

func newAdapter(registry *model.Registry) (*adapter, error) {
	return &adapter{
		registry: registry,
		client:   NewClient(registry),
	}, nil
}

func (a *adapter) Info() (*model.RegistryInfo, error) {
	return &model.RegistryInfo{
		Type: model.RegistryTypeHelmHub,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeChart,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

func (a *adapter) PrepareForPush(resources []*model.Resource) error {
	return errors.New("not supported")
}

// HealthCheck checks health status of a registry
func (a *adapter) HealthCheck() (model.HealthStatus, error) {
	err := a.client.checkHealthy()
	if err == nil {
		return model.Healthy, nil
	}
	return model.Unhealthy, err
}
<commit_msg>Add adapter pattern for helm hub adapter<commit_after>// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package helmhub

import (
	"errors"

	"github.com/goharbor/harbor/src/common/utils/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/model"
)

func init() {
	if err := adp.RegisterFactory(model.RegistryTypeHelmHub, new(factory)); err != nil {
		log.Errorf("failed to register factory for %s: %v", model.RegistryTypeHelmHub, err)
		return
	}
	log.Infof("the factory for adapter %s registered", model.RegistryTypeHelmHub)
}

type factory struct {
}

// Create ...
func (f *factory) Create(r *model.Registry) (adp.Adapter, error) {
	return newAdapter(r)
}

// AdapterPattern ...
func (f *factory) AdapterPattern() *model.AdapterPattern {
	return &model.AdapterPattern{
		EndpointPattern: &model.EndpointPattern{
			EndpointType: model.EndpointPatternTypeFix,
			Endpoints: []*model.Endpoint{
				{
					Key:   "hub.helm.sh",
					Value: "https://hub.helm.sh",
				},
			},
		},
	}
}

type adapter struct {
	registry *model.Registry
	client   *Client
}

func newAdapter(registry *model.Registry) (*adapter, error) {
	return &adapter{
		registry: registry,
		client:   NewClient(registry),
	}, nil
}

func (a *adapter) Info() (*model.RegistryInfo, error) {
	return &model.RegistryInfo{
		Type: model.RegistryTypeHelmHub,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeChart,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

func (a *adapter) PrepareForPush(resources []*model.Resource) error {
	return errors.New("not supported")
}

// HealthCheck checks health status of a registry
func (a *adapter) HealthCheck() (model.HealthStatus, error) {
	err := a.client.checkHealthy()
	if err == nil {
		return model.Healthy, nil
	}
	return model.Unhealthy, err
}
<|endoftext|>