<commit_before>// Package path implements utilities for resolving paths within ipfs.
package path

import (
	"fmt"
	"time"

	mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"

	merkledag "github.com/ipfs/go-ipfs/merkledag"
	u "github.com/ipfs/go-ipfs/util"
)

var log = u.Logger("path")

// ErrNoLink is returned when a link is not found in a path
type ErrNoLink struct {
	name string
	node mh.Multihash
}

func (e ErrNoLink) Error() string {
	return fmt.Sprintf("no link named %q under %s", e.name, e.node.B58String())
}

// Resolver provides path resolution to IPFS
// It has a pointer to a DAGService, which is uses to resolve nodes.
type Resolver struct {
	DAG merkledag.DAGService
}

// SplitAbsPath clean up and split fpath. It extracts the first component (which
// must be a Multihash) and return it separately.
func SplitAbsPath(fpath Path) (mh.Multihash, []string, error) {

	log.Debugf("Resolve: '%s'", fpath)

	parts := fpath.Segments()
	if parts[0] == "ipfs" {
		parts = parts[1:]
	}

	// if nothing, bail.
	if len(parts) == 0 {
		return nil, nil, fmt.Errorf("ipfs path must contain at least one component")
	}

	// first element in the path is a b58 hash (for now)
	h, err := mh.FromB58String(parts[0])
	if err != nil {
		log.Debug("given path element is not a base58 string.\n")
		return nil, nil, err
	}

	return h, parts[1:], nil
}

// ResolvePath fetches the node for given path. It returns the last item
// returned by ResolvePathComponents.
func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (*merkledag.Node, error) {
	nodes, err := s.ResolvePathComponents(ctx, fpath)
	if err != nil || nodes == nil {
		return nil, err
	}
	return nodes[len(nodes)-1], err
}

// ResolvePathComponents fetches the nodes for each segment of the given path.
// It uses the first path component as a hash (key) of the first node, then
// resolves all other components walking the links, with ResolveLinks.
func (s *Resolver) ResolvePathComponents(ctx context.Context, fpath Path) ([]*merkledag.Node, error) {
	h, parts, err := SplitAbsPath(fpath)
	if err != nil {
		return nil, err
	}

	log.Debug("Resolve dag get.")
	ctx, cancel := context.WithTimeout(ctx, time.Minute)
	defer cancel()
	nd, err := s.DAG.Get(ctx, u.Key(h))
	if err != nil {
		return nil, err
	}

	return s.ResolveLinks(ctx, nd, parts)
}

// ResolveLinks iteratively resolves names by walking the link hierarchy.
// Every node is fetched from the DAGService, resolving the next name.
// Returns the list of nodes forming the path, starting with ndd. This list is
// guaranteed never to be empty.
//
// ResolveLinks(nd, []string{"foo", "bar", "baz"})
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
func (s *Resolver) ResolveLinks(ctx context.Context, ndd *merkledag.Node, names []string) ([]*merkledag.Node, error) {

	result := make([]*merkledag.Node, 0, len(names)+1)
	result = append(result, ndd)
	nd := ndd // dup arg workaround

	// for each of the path components
	for _, name := range names {

		var next u.Key
		var nlink *merkledag.Link
		// for each of the links in nd, the current object
		for _, link := range nd.Links {
			if link.Name == name {
				next = u.Key(link.Hash)
				nlink = link
				break
			}
		}

		if next == "" {
			n, _ := nd.Multihash()
			return result, ErrNoLink{name: name, node: n}
		}

		if nlink.Node == nil {
			// fetch object for link and assign to nd
			ctx, cancel := context.WithTimeout(ctx, time.Minute)
			defer cancel()
			nd, err := s.DAG.Get(ctx, next)
			if err != nil {
				return append(result, nd), err
			}
			nlink.Node = nd
		} else {
			nd = nlink.Node
		}

		result = append(result, nlink.Node)
	}
	return result, nil
}
<commit_msg>path/resolver: Fix recursive path resolution<commit_after>// Package path implements utilities for resolving paths within ipfs.
package path

import (
	"fmt"
	"time"

	mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"

	merkledag "github.com/ipfs/go-ipfs/merkledag"
	u "github.com/ipfs/go-ipfs/util"
)

var log = u.Logger("path")

// ErrNoLink is returned when a link is not found in a path
type ErrNoLink struct {
	name string
	node mh.Multihash
}

func (e ErrNoLink) Error() string {
	return fmt.Sprintf("no link named %q under %s", e.name, e.node.B58String())
}

// Resolver provides path resolution to IPFS
// It has a pointer to a DAGService, which is uses to resolve nodes.
type Resolver struct {
	DAG merkledag.DAGService
}

// SplitAbsPath clean up and split fpath. It extracts the first component (which
// must be a Multihash) and return it separately.
func SplitAbsPath(fpath Path) (mh.Multihash, []string, error) {

	log.Debugf("Resolve: '%s'", fpath)

	parts := fpath.Segments()
	if parts[0] == "ipfs" {
		parts = parts[1:]
	}

	// if nothing, bail.
	if len(parts) == 0 {
		return nil, nil, fmt.Errorf("ipfs path must contain at least one component")
	}

	// first element in the path is a b58 hash (for now)
	h, err := mh.FromB58String(parts[0])
	if err != nil {
		log.Debug("given path element is not a base58 string.\n")
		return nil, nil, err
	}

	return h, parts[1:], nil
}

// ResolvePath fetches the node for given path. It returns the last item
// returned by ResolvePathComponents.
func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (*merkledag.Node, error) {
	nodes, err := s.ResolvePathComponents(ctx, fpath)
	if err != nil || nodes == nil {
		return nil, err
	}
	return nodes[len(nodes)-1], err
}

// ResolvePathComponents fetches the nodes for each segment of the given path.
// It uses the first path component as a hash (key) of the first node, then
// resolves all other components walking the links, with ResolveLinks.
func (s *Resolver) ResolvePathComponents(ctx context.Context, fpath Path) ([]*merkledag.Node, error) {
	h, parts, err := SplitAbsPath(fpath)
	if err != nil {
		return nil, err
	}

	log.Debug("Resolve dag get.")
	ctx, cancel := context.WithTimeout(ctx, time.Minute)
	defer cancel()
	nd, err := s.DAG.Get(ctx, u.Key(h))
	if err != nil {
		return nil, err
	}

	return s.ResolveLinks(ctx, nd, parts)
}

// ResolveLinks iteratively resolves names by walking the link hierarchy.
// Every node is fetched from the DAGService, resolving the next name.
// Returns the list of nodes forming the path, starting with ndd. This list is
// guaranteed never to be empty.
//
// ResolveLinks(nd, []string{"foo", "bar", "baz"})
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
func (s *Resolver) ResolveLinks(ctx context.Context, ndd *merkledag.Node, names []string) ([]*merkledag.Node, error) {

	result := make([]*merkledag.Node, 0, len(names)+1)
	result = append(result, ndd)
	nd := ndd // dup arg workaround

	// for each of the path components
	for _, name := range names {

		var next u.Key
		var nlink *merkledag.Link
		// for each of the links in nd, the current object
		for _, link := range nd.Links {
			if link.Name == name {
				next = u.Key(link.Hash)
				nlink = link
				break
			}
		}

		if next == "" {
			n, _ := nd.Multihash()
			return result, ErrNoLink{name: name, node: n}
		}

		if nlink.Node == nil {
			// fetch object for link and assign to nd
			ctx, cancel := context.WithTimeout(ctx, time.Minute)
			defer cancel()
			var err error
			nd, err = s.DAG.Get(ctx, next)
			if err != nil {
				return append(result, nd), err
			}
			nlink.Node = nd
		} else {
			nd = nlink.Node
		}

		result = append(result, nlink.Node)
	}
	return result, nil
}
<|endoftext|>


<commit_before>package smpp34

import (
	"bytes"
	"errors"
)

var (
	// Required SubmitSm Fields
	reqSSMFields = []string{
		SERVICE_TYPE,
		SOURCE_ADDR_TON,
		SOURCE_ADDR_NPI,
		SOURCE_ADDR,
		DEST_ADDR_TON,
		DEST_ADDR_NPI,
		DESTINATION_ADDR,
		ESM_CLASS,
		PROTOCOL_ID,
		PRIORITY_FLAG,
		SCHEDULE_DELIVERY_TIME,
		VALIDITY_PERIOD,
		REGISTERED_DELIVERY,
		REPLACE_IF_PRESENT_FLAG,
		DATA_CODING,
		SM_DEFAULT_MSG_ID,
		SM_LENGTH,
		SHORT_MESSAGE,
	}
)

type SubmitSm struct {
	*Header
	mandatoryFields map[string]Field
	tlvFields       map[uint16]*TLVField
}

func NewSubmitSm(hdr *Header, b []byte) (*SubmitSm, error) {
	r := bytes.NewBuffer(b)

	fields, tlvs, err := create_pdu_fields(reqSSMFields, r)

	if err != nil {
		return nil, err
	}

	s := &SubmitSm{hdr, fields, tlvs}

	return s, nil
}

func (s *SubmitSm) GetField(f string) Field {
	return s.mandatoryFields[f]
}

func (s *SubmitSm) Fields() map[string]Field {
	return s.mandatoryFields
}

func (s *SubmitSm) MandatoryFieldsList() []string {
	return reqSSMFields
}

func (s *SubmitSm) GetHeader() *Header {
	return s.Header
}

func (s *SubmitSm) SetField(f string, v interface{}) error {
	if s.validate_field(f, v) {
		field := NewField(f, v)

		if field != nil {
			s.mandatoryFields[f] = field

			return nil
		}
	}

	return errors.New("Invalid field value")
}

func (s *SubmitSm) SetSeqNum(i uint32) {
	s.Header.Sequence = i
}

func (s *SubmitSm) SetTLVField(t, l int, v []byte) error {
	if l != len(v) {
		return errors.New("Invalid TLV value lenght")
	}

	s.tlvFields[uint16(t)] = &TLVField{uint16(t), uint16(l), v}

	return nil
}

func (s *SubmitSm) validate_field(f string, v interface{}) bool {
	if included_check(s.MandatoryFieldsList(), f) && validate_pdu_field(f, v) {
		return true
	}
	return false
}

func (s *SubmitSm) TLVFields() map[uint16]*TLVField {
	return s.tlvFields
}

func (s *SubmitSm) writeFields() []byte {
	b := []byte{}

	for _, i := range s.MandatoryFieldsList() {
		v := s.mandatoryFields[i].ByteArray()
		b = append(b, v...)
	}

	return b
}

func (s *SubmitSm) writeTLVFields() []byte {
	b := []byte{}

	for _, v := range s.tlvFields {
		b = append(b, v.Writer()...)
	}

	return b
}

func (s *SubmitSm) Writer() []byte {
	b := append(s.writeFields(), s.writeTLVFields()...)
	h := packUi32(uint32(len(b) + 16))
	h = append(h, packUi32(SUBMIT_SM)...)
	h = append(h, packUi32(s.Header.Status)...)
	h = append(h, packUi32(s.Header.Sequence)...)

	return append(h, b...)
}
<commit_msg>Proper SM length set for submit_sm<commit_after>package smpp34

import (
	"bytes"
	"errors"
)

var (
	// Required SubmitSm Fields
	reqSSMFields = []string{
		SERVICE_TYPE,
		SOURCE_ADDR_TON,
		SOURCE_ADDR_NPI,
		SOURCE_ADDR,
		DEST_ADDR_TON,
		DEST_ADDR_NPI,
		DESTINATION_ADDR,
		ESM_CLASS,
		PROTOCOL_ID,
		PRIORITY_FLAG,
		SCHEDULE_DELIVERY_TIME,
		VALIDITY_PERIOD,
		REGISTERED_DELIVERY,
		REPLACE_IF_PRESENT_FLAG,
		DATA_CODING,
		SM_DEFAULT_MSG_ID,
		SM_LENGTH,
		SHORT_MESSAGE,
	}
)

type SubmitSm struct {
	*Header
	mandatoryFields map[string]Field
	tlvFields       map[uint16]*TLVField
}

func NewSubmitSm(hdr *Header, b []byte) (*SubmitSm, error) {
	r := bytes.NewBuffer(b)

	fields, tlvs, err := create_pdu_fields(reqSSMFields, r)

	if err != nil {
		return nil, err
	}

	s := &SubmitSm{hdr, fields, tlvs}

	return s, nil
}

func (s *SubmitSm) GetField(f string) Field {
	return s.mandatoryFields[f]
}

func (s *SubmitSm) Fields() map[string]Field {
	return s.mandatoryFields
}

func (s *SubmitSm) MandatoryFieldsList() []string {
	return reqSSMFields
}

func (s *SubmitSm) GetHeader() *Header {
	return s.Header
}

func (s *SubmitSm) SetField(f string, v interface{}) error {
	if s.validate_field(f, v) {
		field := NewField(f, v)

		if field != nil {
			s.mandatoryFields[f] = field

			return nil
		}
	}

	return errors.New("Invalid field value")
}

func (s *SubmitSm) SetSeqNum(i uint32) {
	s.Header.Sequence = i
}

func (s *SubmitSm) SetTLVField(t, l int, v []byte) error {
	if l != len(v) {
		return errors.New("Invalid TLV value lenght")
	}

	s.tlvFields[uint16(t)] = &TLVField{uint16(t), uint16(l), v}

	return nil
}

func (s *SubmitSm) validate_field(f string, v interface{}) bool {
	if included_check(s.MandatoryFieldsList(), f) && validate_pdu_field(f, v) {
		return true
	}
	return false
}

func (s *SubmitSm) TLVFields() map[uint16]*TLVField {
	return s.tlvFields
}

func (s *SubmitSm) writeFields() []byte {
	b := []byte{}

	for _, i := range s.MandatoryFieldsList() {
		v := s.mandatoryFields[i].ByteArray()
		b = append(b, v...)
	}

	return b
}

func (s *SubmitSm) writeTLVFields() []byte {
	b := []byte{}

	for _, v := range s.tlvFields {
		b = append(b, v.Writer()...)
	}

	return b
}

func (s *SubmitSm) Writer() []byte {
	// Set SM_LENGTH
	sm := len(s.GetField(SHORT_MESSAGE).ByteArray())
	s.SetField(SM_LENGTH, sm)

	b := append(s.writeFields(), s.writeTLVFields()...)
	h := packUi32(uint32(len(b) + 16))
	h = append(h, packUi32(SUBMIT_SM)...)
	h = append(h, packUi32(s.Header.Status)...)
	h = append(h, packUi32(s.Header.Sequence)...)

	return append(h, b...)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes 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 testing

import (
	"testing"

	"k8s.io/apiserver/pkg/storage/storagebackend"

	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/tests/v3/integration"
)

// EtcdTestServer encapsulates the datastructures needed to start local instance for testing
type EtcdTestServer struct {
	CertificatesDir string
	CertFile        string
	KeyFile         string
	CAFile          string

	// The following are lumped etcd3 test server params
	v3Cluster *integration.ClusterV3
	V3Client  *clientv3.Client
}

// Terminate will shutdown the running etcd server
func (m *EtcdTestServer) Terminate(t *testing.T) {
	m.v3Cluster.Terminate(t)
}

// NewUnsecuredEtcd3TestClientServer creates a new client and server for testing
func NewUnsecuredEtcd3TestClientServer(t *testing.T) (*EtcdTestServer, *storagebackend.Config) {
	integration.BeforeTestExternal(t)
	server := &EtcdTestServer{
		v3Cluster: integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1}),
	}
	server.V3Client = server.v3Cluster.RandClient()
	config := &storagebackend.Config{
		Type:   "etcd3",
		Prefix: PathPrefix(),
		Transport: storagebackend.TransportConfig{
			ServerList: server.V3Client.Endpoints(),
		},
		Paging: true,
	}
	return server, config
}
<commit_msg>Quiet embedded etcd logs<commit_after>/*
Copyright 2015 The Kubernetes 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 testing

import (
	"io/ioutil"
	"testing"

	"k8s.io/apiserver/pkg/storage/storagebackend"

	grpclogsettable "github.com/grpc-ecosystem/go-grpc-middleware/logging/settable"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/tests/v3/integration"
	"google.golang.org/grpc/grpclog"
)

var grpc_logger grpclogsettable.SettableLoggerV2

func init() {
	// override logger set up by etcd integration test package
	grpc_logger = grpclogsettable.ReplaceGrpcLoggerV2()
}

// EtcdTestServer encapsulates the datastructures needed to start local instance for testing
type EtcdTestServer struct {
	CertificatesDir string
	CertFile        string
	KeyFile         string
	CAFile          string

	// The following are lumped etcd3 test server params
	v3Cluster *integration.ClusterV3
	V3Client  *clientv3.Client
}

// Terminate will shutdown the running etcd server
func (m *EtcdTestServer) Terminate(t *testing.T) {
	m.v3Cluster.Terminate(t)
}

// NewUnsecuredEtcd3TestClientServer creates a new client and server for testing
func NewUnsecuredEtcd3TestClientServer(t *testing.T) (*EtcdTestServer, *storagebackend.Config) {
	integration.BeforeTestExternal(t)
	grpc_logger.Set(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, &testErrorWriter{t}))
	server := &EtcdTestServer{
		v3Cluster: integration.NewClusterV3(&noLogT{t}, &integration.ClusterConfig{Size: 1}),
	}
	server.V3Client = server.v3Cluster.RandClient()
	config := &storagebackend.Config{
		Type:   "etcd3",
		Prefix: PathPrefix(),
		Transport: storagebackend.TransportConfig{
			ServerList: server.V3Client.Endpoints(),
		},
		Paging: true,
	}
	return server, config
}

type noLogT struct {
	testing.TB
}

func (q *noLogT) Log(s ...interface{}) {
}
func (q *noLogT) Logf(s string, params ...interface{}) {
}

type testErrorWriter struct {
	testing.TB
}

func (t *testErrorWriter) Write(b []byte) (int, error) {
	t.TB.Error(string(b))
	return len(b), nil
}
<|endoftext|>


<commit_before>package limiter

import (
	"math"
	"math/rand"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/stretchr/testify/assert"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

// TestLimiterMemory tests Limiter with memory store.
func TestLimiterMemory(t *testing.T) {
	rate, err := NewRateFromFormatted("3-M")
	assert.Nil(t, err)

	store := NewMemoryStoreWithOptions(StoreOptions{
		Prefix:          "limitertests:memory",
		CleanUpInterval: 30 * time.Second,
	})

	testLimiter(t, store, rate)
}

// TestLimiterRedis tests Limiter with Redis store.
func TestLimiterRedis(t *testing.T) {
	rate, err := NewRateFromFormatted("3-M")
	assert.Nil(t, err)

	randPrefix := RandStringRunes(10)
	store, err := NewRedisStoreWithOptions(
		newRedisPool(),
		StoreOptions{Prefix: "limitertests:redis_" + randPrefix, MaxRetry: 3})

	assert.Nil(t, err)

	testLimiter(t, store, rate)
}

func testLimiter(t *testing.T, store Store, rate Rate) {
	limiter := NewLimiter(store, rate)

	i := 1
	for i <= 5 {
		if i <= 3 {
			ctx, err := limiter.Peek("boo")
			assert.NoError(t, err)
			assert.Equal(t, int64(3-(i-1)), ctx.Remaining)
		}

		ctx, err := limiter.Get("boo")
		assert.NoError(t, err)

		if i <= 3 {
			assert.Equal(t, int64(3), ctx.Limit)
			assert.Equal(t, int64(3-i), ctx.Remaining)
			assert.True(t, math.Ceil(time.Since(time.Unix(ctx.Reset, 0)).Seconds()) <= 60)
			ctx, err := limiter.Peek("boo")
			assert.NoError(t, err)
			assert.Equal(t, int64(3-i), ctx.Remaining)
		} else {
			assert.Equal(t, int64(3), ctx.Limit)
			assert.True(t, ctx.Remaining == 0)
			assert.True(t, math.Ceil(time.Since(time.Unix(ctx.Reset, 0)).Seconds()) <= 60)
		}

		i++
	}

}

// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------

// newRedisPool returns
func newRedisPool() *redis.Pool {
	return redis.NewPool(func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", ":6379")
		if err != nil {
			return nil, err
		}
		return c, err
	}, 100)
}

// newRedisLimiter returns an instance of limiter with redis backend.
func newRedisLimiter(formattedQuota string, prefix string) *Limiter {
	rate, err := NewRateFromFormatted(formattedQuota)
	if err != nil {
		panic(err)
	}

	store, err := NewRedisStoreWithOptions(
		newRedisPool(),
		StoreOptions{Prefix: prefix, MaxRetry: 3})

	if err != nil {
		panic(err)
	}

	return NewLimiter(store, rate)
}
<commit_msg>chore: delete store and middleware unit test<commit_after><|endoftext|>


<commit_before>/*
 * ZDNS Copyright 2016 Regents of the University of Michigan
 *
 * 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 alookup

import (
	"errors"
	"flag"
	"net"
	"strings"

	"github.com/zmap/dns"
	"github.com/zmap/zdns"
	"github.com/zmap/zdns/modules/miekg"
)

type Result struct {
	IPv4Addresses []string `json:"ipv4_addresses,omitempty" groups:"short,normal,long,trace"`
	IPv6Addresses []string `json:"ipv6_addresses,omitempty" groups:"short,normal,long,trace"`
}

// Per Connection Lookup ======================================================
//
type Lookup struct {
	Factory *RoutineLookupFactory
	miekg.Lookup
}

func (s *Lookup) DoLookup(name, nameServer string) (interface{}, zdns.Trace, zdns.Status, error) {
	if nameServer == "" {
		nameServer = s.Factory.Factory.RandomNameServer()
	}
	return s.DoTargetedLookup(name, nameServer)
}

// Verify that A record is indeed IPv4 and AAAA is IPv6
func verifyAddress(ansType string, ip string) bool {
	var isIpv4, isIpv6 bool
	if net.ParseIP(ip) != nil {
		isIpv6 = strings.Contains(ip, ":")
		isIpv4 = !isIpv6
	}
	if ansType == "A" {
		return isIpv4
	} else if ansType == "AAAA" {
		return isIpv6
	}
	return !isIpv4 && !isIpv6
}

func populateResults(records []interface{}, dnsType uint16, candidateSet map[string][]miekg.Answer, cnameSet map[string][]miekg.Answer, garbage map[string][]miekg.Answer) {
	for _, a := range records {
		// filter only valid answers of requested type or CNAME (#163)
		if ans, ok := a.(miekg.Answer); ok {
			lowerCaseName := strings.ToLower(ans.Name)
			// Verify that the answer type matches requested type
			if verifyAddress(ans.Type, ans.Answer) {
				ansType := dns.StringToType[ans.Type]
				if dnsType == ansType {
					candidateSet[lowerCaseName] = append(candidateSet[lowerCaseName], ans)
				} else if ok && dns.TypeCNAME == ansType {
					cnameSet[lowerCaseName] = append(cnameSet[lowerCaseName], ans)
				} else {
					garbage[lowerCaseName] = append(garbage[lowerCaseName], ans)
				}
			} else {
				garbage[lowerCaseName] = append(garbage[lowerCaseName], ans)
			}
		}
	}
}

func (s *Lookup) doLookupProtocol(name, nameServer string, dnsType uint16, candidateSet map[string][]miekg.Answer, cnameSet map[string][]miekg.Answer, origName string, depth int) ([]string, []interface{}, zdns.Status, error) {
	// avoid infinite loops
	if name == origName && depth != 0 {
		return nil, make([]interface{}, 0), zdns.STATUS_ERROR, errors.New("infinite redirection loop")
	}
	if depth > 10 {
		return nil, make([]interface{}, 0), zdns.STATUS_ERROR, errors.New("max recursion depth reached")
	}
	// check if the record is already in our cache. if not, perform normal A lookup and
	// see what comes back. Then iterate over results and if needed, perform further lookups
	var trace []interface{}
	garbage := map[string][]miekg.Answer{}
	if _, ok := candidateSet[name]; !ok {
		var miekgResult interface{}
		var status zdns.Status
		var err error
		miekgResult, trace, status, err = s.DoMiekgLookup(miekg.Question{Name: name, Type: dnsType}, nameServer)
		if status != zdns.STATUS_NOERROR || err != nil {
			return nil, trace, status, err
		}

		populateResults(miekgResult.(miekg.Result).Answers, dnsType, candidateSet, cnameSet, garbage)
		populateResults(miekgResult.(miekg.Result).Additional, dnsType, candidateSet, cnameSet, garbage)
	}
	// our cache should now have any data that exists about the current name
	if res, ok := candidateSet[name]; ok && len(res) > 0 {
		// we have IP addresses to hand back to the user. let's make an easy-to-use array of strings
		var ips []string
		for _, answer := range res {
			ips = append(ips, answer.Answer)
		}
		return ips, trace, zdns.STATUS_NOERROR, nil
	} else if res, ok = cnameSet[name]; ok && len(res) > 0 {
		// we have a CNAME and need to further recurse to find IPs
		shortName := strings.ToLower(res[0].Answer[0 : len(res[0].Answer)-1])
		res, secondTrace, status, err := s.doLookupProtocol(shortName, nameServer, dnsType, candidateSet, cnameSet, origName, depth+1)
		trace = append(trace, secondTrace...)
		return res, trace, status, err
	} else if res, ok = garbage[name]; ok && len(res) > 0 {
		return nil, trace, zdns.STATUS_ERROR, errors.New("unexpected record type received")
	} else {
		// we have no data whatsoever about this name. return an empty recordset to the user
		var ips []string
		return ips, trace, zdns.STATUS_NOERROR, nil
	}
}

func safeStatus(status zdns.Status) bool {
	return status == zdns.STATUS_NOERROR
}

func (s *Lookup) DoTargetedLookup(name, nameServer string) (interface{}, []interface{}, zdns.Status, error) {
	res := Result{}
	candidateSet := map[string][]miekg.Answer{}
	cnameSet := map[string][]miekg.Answer{}
	lookupIpv4 := s.Factory.Factory.IPv4Lookup || !s.Factory.Factory.IPv6Lookup
	lookupIpv6 := s.Factory.Factory.IPv6Lookup
	var ipv4 []string
	var ipv6 []string
	var ipv4Trace []interface{}
	var ipv6Trace []interface{}
	var ipv4status zdns.Status
	var ipv6status zdns.Status
	if lookupIpv4 {
		ipv4, ipv4Trace, ipv4status, _ = s.doLookupProtocol(name, nameServer, dns.TypeA, candidateSet, cnameSet, name, 0)
		res.IPv4Addresses = make([]string, len(ipv4))
		copy(res.IPv4Addresses, ipv4)
	}
	candidateSet = map[string][]miekg.Answer{}
	cnameSet = map[string][]miekg.Answer{}
	if lookupIpv6 {
		ipv6, ipv6Trace, ipv6status, _ = s.doLookupProtocol(name, nameServer, dns.TypeAAAA, candidateSet, cnameSet, name, 0)
		res.IPv6Addresses = make([]string, len(ipv6))
		copy(res.IPv6Addresses, ipv6)
	}

	combinedTrace := append(ipv4Trace, ipv6Trace...)

	// alookup is only expected to return IP addresses. Hence irrespective of the
	// status returned from miekgdns, we return NO_ANSWER in case of missing IPs
	if len(res.IPv4Addresses) == 0 && len(res.IPv6Addresses) == 0 {
		if lookupIpv4 && !safeStatus(ipv4status) {
			return nil, combinedTrace, ipv4status, nil
		} else if lookupIpv6 && !safeStatus(ipv6status) {
			return nil, combinedTrace, ipv6status, nil
		} else {
			return nil, combinedTrace, zdns.STATUS_NOERROR, nil
		}
	}
	return res, combinedTrace, zdns.STATUS_NOERROR, nil
}

// Per GoRoutine Factory ======================================================
//
type RoutineLookupFactory struct {
	miekg.RoutineLookupFactory
	Factory *GlobalLookupFactory
}

func (s *RoutineLookupFactory) MakeLookup() (zdns.Lookup, error) {
	a := Lookup{Factory: s}
	nameServer := s.Factory.RandomNameServer()
	a.Initialize(nameServer, dns.TypeA, dns.ClassINET, &s.RoutineLookupFactory)
	return &a, nil
}

// Global Factory =============================================================
//
type GlobalLookupFactory struct {
	miekg.GlobalLookupFactory
	IPv4Lookup bool
	IPv6Lookup bool
}

func (s *GlobalLookupFactory) AddFlags(f *flag.FlagSet) {
	f.BoolVar(&s.IPv4Lookup, "ipv4-lookup", false, "perform A lookups for each server")
	f.BoolVar(&s.IPv6Lookup, "ipv6-lookup", false, "perform AAAA record lookups for each server")
}

// Command-line Help Documentation. This is the descriptive text what is
// returned when you run zdns module --help
func (s *GlobalLookupFactory) Help() string {
	return ""
}

func (s *GlobalLookupFactory) MakeRoutineFactory(threadID int) (zdns.RoutineLookupFactory, error) {
	r := new(RoutineLookupFactory)
	r.Factory = s
	r.RoutineLookupFactory.Factory = &s.GlobalLookupFactory
	r.Initialize(s.GlobalConf)
	r.ThreadID = threadID
	return r, nil
}

// Global Registration ========================================================
//
func init() {
	s := new(GlobalLookupFactory)
	zdns.RegisterLookup("ALOOKUP", s)
}
<commit_msg>Initialize bools to false<commit_after>/*
 * ZDNS Copyright 2016 Regents of the University of Michigan
 *
 * 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 alookup

import (
	"errors"
	"flag"
	"net"
	"strings"

	"github.com/zmap/dns"
	"github.com/zmap/zdns"
	"github.com/zmap/zdns/modules/miekg"
)

type Result struct {
	IPv4Addresses []string `json:"ipv4_addresses,omitempty" groups:"short,normal,long,trace"`
	IPv6Addresses []string `json:"ipv6_addresses,omitempty" groups:"short,normal,long,trace"`
}

// Per Connection Lookup ======================================================
//
type Lookup struct {
	Factory *RoutineLookupFactory
	miekg.Lookup
}

func (s *Lookup) DoLookup(name, nameServer string) (interface{}, zdns.Trace, zdns.Status, error) {
	if nameServer == "" {
		nameServer = s.Factory.Factory.RandomNameServer()
	}
	return s.DoTargetedLookup(name, nameServer)
}

// Verify that A record is indeed IPv4 and AAAA is IPv6
func verifyAddress(ansType string, ip string) bool {
	isIpv4 := false
	isIpv6 := false
	if net.ParseIP(ip) != nil {
		isIpv6 = strings.Contains(ip, ":")
		isIpv4 = !isIpv6
	}
	if ansType == "A" {
		return isIpv4
	} else if ansType == "AAAA" {
		return isIpv6
	}
	return !isIpv4 && !isIpv6
}

func populateResults(records []interface{}, dnsType uint16, candidateSet map[string][]miekg.Answer, cnameSet map[string][]miekg.Answer, garbage map[string][]miekg.Answer) {
	for _, a := range records {
		// filter only valid answers of requested type or CNAME (#163)
		if ans, ok := a.(miekg.Answer); ok {
			lowerCaseName := strings.ToLower(ans.Name)
			// Verify that the answer type matches requested type
			if verifyAddress(ans.Type, ans.Answer) {
				ansType := dns.StringToType[ans.Type]
				if dnsType == ansType {
					candidateSet[lowerCaseName] = append(candidateSet[lowerCaseName], ans)
				} else if ok && dns.TypeCNAME == ansType {
					cnameSet[lowerCaseName] = append(cnameSet[lowerCaseName], ans)
				} else {
					garbage[lowerCaseName] = append(garbage[lowerCaseName], ans)
				}
			} else {
				garbage[lowerCaseName] = append(garbage[lowerCaseName], ans)
			}
		}
	}
}

func (s *Lookup) doLookupProtocol(name, nameServer string, dnsType uint16, candidateSet map[string][]miekg.Answer, cnameSet map[string][]miekg.Answer, origName string, depth int) ([]string, []interface{}, zdns.Status, error) {
	// avoid infinite loops
	if name == origName && depth != 0 {
		return nil, make([]interface{}, 0), zdns.STATUS_ERROR, errors.New("infinite redirection loop")
	}
	if depth > 10 {
		return nil, make([]interface{}, 0), zdns.STATUS_ERROR, errors.New("max recursion depth reached")
	}
	// check if the record is already in our cache. if not, perform normal A lookup and
	// see what comes back. Then iterate over results and if needed, perform further lookups
	var trace []interface{}
	garbage := map[string][]miekg.Answer{}
	if _, ok := candidateSet[name]; !ok {
		var miekgResult interface{}
		var status zdns.Status
		var err error
		miekgResult, trace, status, err = s.DoMiekgLookup(miekg.Question{Name: name, Type: dnsType}, nameServer)
		if status != zdns.STATUS_NOERROR || err != nil {
			return nil, trace, status, err
		}

		populateResults(miekgResult.(miekg.Result).Answers, dnsType, candidateSet, cnameSet, garbage)
		populateResults(miekgResult.(miekg.Result).Additional, dnsType, candidateSet, cnameSet, garbage)
	}
	// our cache should now have any data that exists about the current name
	if res, ok := candidateSet[name]; ok && len(res) > 0 {
		// we have IP addresses to hand back to the user. let's make an easy-to-use array of strings
		var ips []string
		for _, answer := range res {
			ips = append(ips, answer.Answer)
		}
		return ips, trace, zdns.STATUS_NOERROR, nil
	} else if res, ok = cnameSet[name]; ok && len(res) > 0 {
		// we have a CNAME and need to further recurse to find IPs
		shortName := strings.ToLower(res[0].Answer[0 : len(res[0].Answer)-1])
		res, secondTrace, status, err := s.doLookupProtocol(shortName, nameServer, dnsType, candidateSet, cnameSet, origName, depth+1)
		trace = append(trace, secondTrace...)
		return res, trace, status, err
	} else if res, ok = garbage[name]; ok && len(res) > 0 {
		return nil, trace, zdns.STATUS_ERROR, errors.New("unexpected record type received")
	} else {
		// we have no data whatsoever about this name. return an empty recordset to the user
		var ips []string
		return ips, trace, zdns.STATUS_NOERROR, nil
	}
}

func safeStatus(status zdns.Status) bool {
	return status == zdns.STATUS_NOERROR
}

func (s *Lookup) DoTargetedLookup(name, nameServer string) (interface{}, []interface{}, zdns.Status, error) {
	res := Result{}
	candidateSet := map[string][]miekg.Answer{}
	cnameSet := map[string][]miekg.Answer{}
	lookupIpv4 := s.Factory.Factory.IPv4Lookup || !s.Factory.Factory.IPv6Lookup
	lookupIpv6 := s.Factory.Factory.IPv6Lookup
	var ipv4 []string
	var ipv6 []string
	var ipv4Trace []interface{}
	var ipv6Trace []interface{}
	var ipv4status zdns.Status
	var ipv6status zdns.Status
	if lookupIpv4 {
		ipv4, ipv4Trace, ipv4status, _ = s.doLookupProtocol(name, nameServer, dns.TypeA, candidateSet, cnameSet, name, 0)
		res.IPv4Addresses = make([]string, len(ipv4))
		copy(res.IPv4Addresses, ipv4)
	}
	candidateSet = map[string][]miekg.Answer{}
	cnameSet = map[string][]miekg.Answer{}
	if lookupIpv6 {
		ipv6, ipv6Trace, ipv6status, _ = s.doLookupProtocol(name, nameServer, dns.TypeAAAA, candidateSet, cnameSet, name, 0)
		res.IPv6Addresses = make([]string, len(ipv6))
		copy(res.IPv6Addresses, ipv6)
	}

	combinedTrace := append(ipv4Trace, ipv6Trace...)

	// alookup is only expected to return IP addresses. Hence irrespective of the
	// status returned from miekgdns, we return NO_ANSWER in case of missing IPs
	if len(res.IPv4Addresses) == 0 && len(res.IPv6Addresses) == 0 {
		if lookupIpv4 && !safeStatus(ipv4status) {
			return nil, combinedTrace, ipv4status, nil
		} else if lookupIpv6 && !safeStatus(ipv6status) {
			return nil, combinedTrace, ipv6status, nil
		} else {
			return nil, combinedTrace, zdns.STATUS_NOERROR, nil
		}
	}
	return res, combinedTrace, zdns.STATUS_NOERROR, nil
}

// Per GoRoutine Factory ======================================================
//
type RoutineLookupFactory struct {
	miekg.RoutineLookupFactory
	Factory *GlobalLookupFactory
}

func (s *RoutineLookupFactory) MakeLookup() (zdns.Lookup, error) {
	a := Lookup{Factory: s}
	nameServer := s.Factory.RandomNameServer()
	a.Initialize(nameServer, dns.TypeA, dns.ClassINET, &s.RoutineLookupFactory)
	return &a, nil
}

// Global Factory =============================================================
//
type GlobalLookupFactory struct {
	miekg.GlobalLookupFactory
	IPv4Lookup bool
	IPv6Lookup bool
}

func (s *GlobalLookupFactory) AddFlags(f *flag.FlagSet) {
	f.BoolVar(&s.IPv4Lookup, "ipv4-lookup", false, "perform A lookups for each server")
	f.BoolVar(&s.IPv6Lookup, "ipv6-lookup", false, "perform AAAA record lookups for each server")
}

// Command-line Help Documentation. This is the descriptive text what is
// returned when you run zdns module --help
func (s *GlobalLookupFactory) Help() string {
	return ""
}

func (s *GlobalLookupFactory) MakeRoutineFactory(threadID int) (zdns.RoutineLookupFactory, error) {
	r := new(RoutineLookupFactory)
	r.Factory = s
	r.RoutineLookupFactory.Factory = &s.GlobalLookupFactory
	r.Initialize(s.GlobalConf)
	r.ThreadID = threadID
	return r, nil
}

// Global Registration ========================================================
//
func init() {
	s := new(GlobalLookupFactory)
	zdns.RegisterLookup("ALOOKUP", s)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pkginit

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/noder"
	"cmd/compile/internal/objw"
	"cmd/compile/internal/staticinit"
	"cmd/compile/internal/typecheck"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
)

// MakeInit creates a synthetic init function to handle any
// package-scope initialization statements.
//
// TODO(mdempsky): Move into noder, so that the types2-based frontends
// can use Info.InitOrder instead.
func MakeInit() {
	nf := initOrder(typecheck.Target.Decls)
	if len(nf) == 0 {
		return
	}

	// Make a function that contains all the initialization statements.
	base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
	initializers := typecheck.Lookup("init")
	fn := typecheck.DeclFunc(initializers, nil, nil, nil)
	for _, dcl := range typecheck.InitTodoFunc.Dcl {
		dcl.Curfn = fn
	}
	fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
	typecheck.InitTodoFunc.Dcl = nil

	// Suppress useless "can inline" diagnostics.
	// Init functions are only called dynamically.
	fn.SetInlinabilityChecked(true)

	fn.Body = nf
	typecheck.FinishFuncBody()

	typecheck.Func(fn)
	ir.WithFunc(fn, func() {
		typecheck.Stmts(nf)
	})
	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)

	// Prepend to Inits, so it runs first, before any user-declared init
	// functions.
	typecheck.Target.Inits = append([]*ir.Func{fn}, typecheck.Target.Inits...)

	if typecheck.InitTodoFunc.Dcl != nil {
		// We only generate temps using InitTodoFunc if there
		// are package-scope initialization statements, so
		// something's weird if we get here.
		base.Fatalf("InitTodoFunc still has declarations")
	}
	typecheck.InitTodoFunc = nil
}

// Task makes and returns an initialization record for the package.
// See runtime/proc.go:initTask for its layout.
// The 3 tasks for initialization are:
//  1. Initialize all of the packages the current package depends on.
//  2. Initialize all the variables that have initializers.
//  3. Run any init functions.
func Task() *ir.Name {
	var deps []*obj.LSym // initTask records for packages the current package depends on
	var fns []*obj.LSym  // functions to call for package initialization

	// Find imported packages with init tasks.
	for _, pkg := range typecheck.Target.Imports {
		n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
		if n.Op() == ir.ONONAME {
			continue
		}
		if n.Op() != ir.ONAME || n.(*ir.Name).Class != ir.PEXTERN {
			base.Fatalf("bad inittask: %v", n)
		}
		deps = append(deps, n.(*ir.Name).Linksym())
	}
	if base.Flag.ASan {
		// Make an initialization function to call runtime.asanregisterglobals to register an
		// array of instrumented global variables when -asan is enabled. An instrumented global
		// variable is described by a structure.
		// See the _asan_global structure declared in src/runtime/asan/asan.go.
		//
		// func init {
		// 		var globals []_asan_global {...}
		// 		asanregisterglobals(&globals[0], len(globals))
		// }
		for _, n := range typecheck.Target.Externs {
			if canInstrumentGlobal(n) {
				name := n.Sym().Name
				InstrumentGlobalsMap[name] = n
				InstrumentGlobalsSlice = append(InstrumentGlobalsSlice, n)
			}
		}
		ni := len(InstrumentGlobalsMap)
		if ni != 0 {
			// Make an init._ function.
			base.Pos = base.AutogeneratedPos
			typecheck.DeclContext = ir.PEXTERN
			name := noder.Renameinit()
			fnInit := typecheck.DeclFunc(name, ir.NewFuncType(base.Pos, nil, nil, nil))

			// Get an array of intrumented global variables.
			globals := instrumentGlobals(fnInit)

			// Call runtime.asanregisterglobals function to poison redzones.
			// runtime.asanregisterglobals(unsafe.Pointer(&globals[0]), ni)
			asanf := typecheck.NewName(ir.Pkgs.Runtime.Lookup("asanregisterglobals"))
			ir.MarkFunc(asanf)
			asanf.SetType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{
				types.NewField(base.Pos, nil, types.Types[types.TUNSAFEPTR]),
				types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
			}, nil))
			asancall := ir.NewCallExpr(base.Pos, ir.OCALL, asanf, nil)
			asancall.Args.Append(typecheck.ConvNop(typecheck.NodAddr(
				ir.NewIndexExpr(base.Pos, globals, ir.NewInt(0))), types.Types[types.TUNSAFEPTR]))
			asancall.Args.Append(typecheck.ConvNop(ir.NewInt(int64(ni)), types.Types[types.TUINTPTR]))

			fnInit.Body.Append(asancall)
			typecheck.FinishFuncBody()
			typecheck.Func(fnInit)
			ir.CurFunc = fnInit
			typecheck.Stmts(fnInit.Body)
			ir.CurFunc = nil

			typecheck.Target.Decls = append(typecheck.Target.Decls, fnInit)
			typecheck.Target.Inits = append(typecheck.Target.Inits, fnInit)
		}
	}

	// Record user init functions.
	for _, fn := range typecheck.Target.Inits {
		if fn.Sym().Name == "init" {
			// Synthetic init function for initialization of package-scope
			// variables. We can use staticinit to optimize away static
			// assignments.
			s := staticinit.Schedule{
				Plans: make(map[ir.Node]*staticinit.Plan),
				Temps: make(map[ir.Node]*ir.Name),
			}
			for _, n := range fn.Body {
				s.StaticInit(n)
			}
			fn.Body = s.Out
			ir.WithFunc(fn, func() {
				typecheck.Stmts(fn.Body)
			})

			if len(fn.Body) == 0 {
				fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
			}
		}

		// Skip init functions with empty bodies.
		if len(fn.Body) == 1 {
			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
				continue
			}
		}
		fns = append(fns, fn.Nname.Linksym())
	}

	if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Name != "main" && types.LocalPkg.Name != "runtime" {
		return nil // nothing to initialize
	}

	// Make an .inittask structure.
	sym := typecheck.Lookup(".inittask")
	task := typecheck.NewName(sym)
	task.SetType(types.Types[types.TUINT8]) // fake type
	task.Class = ir.PEXTERN
	sym.Def = task
	lsym := task.Linksym()
	ot := 0
	ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
	ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
	ot = objw.Uintptr(lsym, ot, uint64(len(fns)))
	for _, d := range deps {
		ot = objw.SymPtr(lsym, ot, d, 0)
	}
	for _, f := range fns {
		ot = objw.SymPtr(lsym, ot, f, 0)
	}
	// An initTask has pointers, but none into the Go heap.
	// It's not quite read only, the state field must be modifiable.
	objw.Global(lsym, int32(ot), obj.NOPTR)
	return task
}
<commit_msg>cmd/compile/internal/pkginit: fix typecheck.DeclFunc call<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pkginit

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/noder"
	"cmd/compile/internal/objw"
	"cmd/compile/internal/staticinit"
	"cmd/compile/internal/typecheck"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
)

// MakeInit creates a synthetic init function to handle any
// package-scope initialization statements.
//
// TODO(mdempsky): Move into noder, so that the types2-based frontends
// can use Info.InitOrder instead.
func MakeInit() {
	nf := initOrder(typecheck.Target.Decls)
	if len(nf) == 0 {
		return
	}

	// Make a function that contains all the initialization statements.
	base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
	initializers := typecheck.Lookup("init")
	fn := typecheck.DeclFunc(initializers, nil, nil, nil)
	for _, dcl := range typecheck.InitTodoFunc.Dcl {
		dcl.Curfn = fn
	}
	fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
	typecheck.InitTodoFunc.Dcl = nil

	// Suppress useless "can inline" diagnostics.
	// Init functions are only called dynamically.
	fn.SetInlinabilityChecked(true)

	fn.Body = nf
	typecheck.FinishFuncBody()

	typecheck.Func(fn)
	ir.WithFunc(fn, func() {
		typecheck.Stmts(nf)
	})
	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)

	// Prepend to Inits, so it runs first, before any user-declared init
	// functions.
	typecheck.Target.Inits = append([]*ir.Func{fn}, typecheck.Target.Inits...)

	if typecheck.InitTodoFunc.Dcl != nil {
		// We only generate temps using InitTodoFunc if there
		// are package-scope initialization statements, so
		// something's weird if we get here.
		base.Fatalf("InitTodoFunc still has declarations")
	}
	typecheck.InitTodoFunc = nil
}

// Task makes and returns an initialization record for the package.
// See runtime/proc.go:initTask for its layout.
// The 3 tasks for initialization are:
//  1. Initialize all of the packages the current package depends on.
//  2. Initialize all the variables that have initializers.
//  3. Run any init functions.
func Task() *ir.Name {
	var deps []*obj.LSym // initTask records for packages the current package depends on
	var fns []*obj.LSym  // functions to call for package initialization

	// Find imported packages with init tasks.
	for _, pkg := range typecheck.Target.Imports {
		n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
		if n.Op() == ir.ONONAME {
			continue
		}
		if n.Op() != ir.ONAME || n.(*ir.Name).Class != ir.PEXTERN {
			base.Fatalf("bad inittask: %v", n)
		}
		deps = append(deps, n.(*ir.Name).Linksym())
	}
	if base.Flag.ASan {
		// Make an initialization function to call runtime.asanregisterglobals to register an
		// array of instrumented global variables when -asan is enabled. An instrumented global
		// variable is described by a structure.
		// See the _asan_global structure declared in src/runtime/asan/asan.go.
		//
		// func init {
		// 		var globals []_asan_global {...}
		// 		asanregisterglobals(&globals[0], len(globals))
		// }
		for _, n := range typecheck.Target.Externs {
			if canInstrumentGlobal(n) {
				name := n.Sym().Name
				InstrumentGlobalsMap[name] = n
				InstrumentGlobalsSlice = append(InstrumentGlobalsSlice, n)
			}
		}
		ni := len(InstrumentGlobalsMap)
		if ni != 0 {
			// Make an init._ function.
			base.Pos = base.AutogeneratedPos
			typecheck.DeclContext = ir.PEXTERN
			name := noder.Renameinit()
			fnInit := typecheck.DeclFunc(name, nil, nil, nil)

			// Get an array of intrumented global variables.
			globals := instrumentGlobals(fnInit)

			// Call runtime.asanregisterglobals function to poison redzones.
			// runtime.asanregisterglobals(unsafe.Pointer(&globals[0]), ni)
			asanf := typecheck.NewName(ir.Pkgs.Runtime.Lookup("asanregisterglobals"))
			ir.MarkFunc(asanf)
			asanf.SetType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{
				types.NewField(base.Pos, nil, types.Types[types.TUNSAFEPTR]),
				types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
			}, nil))
			asancall := ir.NewCallExpr(base.Pos, ir.OCALL, asanf, nil)
			asancall.Args.Append(typecheck.ConvNop(typecheck.NodAddr(
				ir.NewIndexExpr(base.Pos, globals, ir.NewInt(0))), types.Types[types.TUNSAFEPTR]))
			asancall.Args.Append(typecheck.ConvNop(ir.NewInt(int64(ni)), types.Types[types.TUINTPTR]))

			fnInit.Body.Append(asancall)
			typecheck.FinishFuncBody()
			typecheck.Func(fnInit)
			ir.CurFunc = fnInit
			typecheck.Stmts(fnInit.Body)
			ir.CurFunc = nil

			typecheck.Target.Decls = append(typecheck.Target.Decls, fnInit)
			typecheck.Target.Inits = append(typecheck.Target.Inits, fnInit)
		}
	}

	// Record user init functions.
	for _, fn := range typecheck.Target.Inits {
		if fn.Sym().Name == "init" {
			// Synthetic init function for initialization of package-scope
			// variables. We can use staticinit to optimize away static
			// assignments.
			s := staticinit.Schedule{
				Plans: make(map[ir.Node]*staticinit.Plan),
				Temps: make(map[ir.Node]*ir.Name),
			}
			for _, n := range fn.Body {
				s.StaticInit(n)
			}
			fn.Body = s.Out
			ir.WithFunc(fn, func() {
				typecheck.Stmts(fn.Body)
			})

			if len(fn.Body) == 0 {
				fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
			}
		}

		// Skip init functions with empty bodies.
		if len(fn.Body) == 1 {
			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
				continue
			}
		}
		fns = append(fns, fn.Nname.Linksym())
	}

	if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Name != "main" && types.LocalPkg.Name != "runtime" {
		return nil // nothing to initialize
	}

	// Make an .inittask structure.
	sym := typecheck.Lookup(".inittask")
	task := typecheck.NewName(sym)
	task.SetType(types.Types[types.TUINT8]) // fake type
	task.Class = ir.PEXTERN
	sym.Def = task
	lsym := task.Linksym()
	ot := 0
	ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
	ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
	ot = objw.Uintptr(lsym, ot, uint64(len(fns)))
	for _, d := range deps {
		ot = objw.SymPtr(lsym, ot, d, 0)
	}
	for _, f := range fns {
		ot = objw.SymPtr(lsym, ot, f, 0)
	}
	// An initTask has pointers, but none into the Go heap.
	// It's not quite read only, the state field must be modifiable.
	objw.Global(lsym, int32(ot), obj.NOPTR)
	return task
}
<|endoftext|>


<commit_before>package pinnedpost

import (
	"socialapi/models"

	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

type Controller struct{ log logging.Logger }

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func New(log logging.Logger) *Controller {
	return &Controller{log: log}
}

func (c *Controller) ReplyCreated(messageReply *models.MessageReply) error {
	// parent message is needed for adding to pinned channel
	parentMessage := models.NewChannelMessage()
	if err := parentMessage.ById(messageReply.MessageId); err != nil {
		return err
	}

	// only posts can be marked as pinned
	if parentMessage.TypeConstant != models.ChannelMessage_TYPE_POST {
		return nil
	}

	// fetch reply itself for processsing
	reply := models.NewChannelMessage()
	if err := reply.ById(messageReply.ReplyId); err != nil {
		return err
	}

	// fetch the parent channel for gorup name
	// get it from cache
	channel, err := models.ChannelById(reply.InitialChannelId)
	if err != nil {
		return err
	}

	// get pinning channel for current user
	pinningChannel, err := models.EnsurePinnedActivityChannel(reply.AccountId, channel.GroupName)
	if err != nil {
		return err
	}

	// add parent message into pinning channel
	_, err = pinningChannel.AddMessage(parentMessage.Id)
	// if message is already in the channel ignore the error, and mark process as successful
	if err == models.AlreadyInTheChannel {
		return nil
	}

	return err
}
<commit_msg>Social: add message created event into system for adding created messages to owner's pinned post<commit_after>package pinnedpost

import (
	"socialapi/models"

	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

type Controller struct{ log logging.Logger }

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func New(log logging.Logger) *Controller {
	return &Controller{log: log}
}

// MessageCreated handles the created messages
// adds given message to the the author's pinned post channel
func (c *Controller) MessageCreated(message *models.ChannelMessage) error {
	// only posts can be marked as pinned
	if message.TypeConstant != models.ChannelMessage_TYPE_POST {
		return nil
	}

	return c.addMessage(message.AccountId, message.Id, message.InitialChannelId)
}

// MessageReplyCreated handles the created replies
func (c *Controller) MessageReplyCreated(messageReply *models.MessageReply) error {
	parent, err := messageReply.FetchParent()
	if err != nil {
		return err
	}

	// only posts can be marked as pinned
	if parent.TypeConstant != models.ChannelMessage_TYPE_POST {
		return nil
	}

	reply, err := messageReply.FetchReply()
	if err != nil {
		return err
	}

	return c.addMessage(reply.AccountId, parent.Id, parent.InitialChannelId)
}

func (c *Controller) addMessage(accountId, messageId, channelId int64) error {
	// fetch the parent channel for gorup name
	// get it from cache
	channel, err := models.ChannelById(channelId)
	if err != nil {
		return err
	}

	// get pinning channel for current user if it is created,, else create and get
	pinningChannel, err := models.EnsurePinnedActivityChannel(accountId, channel.GroupName)
	if err != nil {
		return err
	}

	// add parent message into pinning channel
	_, err = pinningChannel.AddMessage(messageId)
	// if message is already in the channel ignore the error, and mark process as successful
	if err == models.AlreadyInTheChannel {
		return nil
	}

	return err
}
<|endoftext|>


<commit_before>package realtime

import (
	"errors"
	"fmt"
	"socialapi/models"
)

type channelUpdatedEventType string

var (
	channelUpdatedEventMessageAddedToChannel     channelUpdatedEventType = "MessageAddedToChannel"
	channelUpdatedEventMessageRemovedFromChannel channelUpdatedEventType = "MessageRemovedFromChannel"
	channelUpdatedEventMessageUpdatedAtChannel   channelUpdatedEventType = "MessageListUpdated"
	channelUpdatedEventReplyAdded                channelUpdatedEventType = "ReplyAdded"
	channelUpdatedEventReplyRemoved              channelUpdatedEventType = "ReplyRemoved"
	channelUpdatedEventChannelParticipantUpdated channelUpdatedEventType = "ParticipantUpdated"
)

type channelUpdatedEvent struct {
	Controller           *Controller                `json:"-"`
	Channel              *models.Channel            `json:"channel"`
	ParentChannelMessage *models.ChannelMessage     `json:"channelMessage"`
	ReplyChannelMessage  *models.ChannelMessage     `json:"-"`
	EventType            channelUpdatedEventType    `json:"event"`
	ChannelParticipant   *models.ChannelParticipant `json:"-"`
	UnreadCount          int                        `json:"unreadCount"`
}

// sendChannelUpdatedEvent sends channel updated events
func (cue *channelUpdatedEvent) send() error {
	cue.Controller.log.Debug("sending channel update event %+v", cue)

	if err := cue.validateChannelUpdatedEvents(); err != nil {
		cue.Controller.log.Error(err.Error())
		// this is not an error actually
		return nil
	}

	// fetch all participants of related channel
	// if you ask why we are not sending those messaages to the channel's channel
	// instead of sending events as notifications?, because we are also sending
	// unread counts of the related channel's messages by the notifiee
	participants, err := cue.Channel.FetchParticipantIds()
	if err != nil {
		cue.Controller.log.Error("Error occured while fetching participants %s", err.Error())
		return err
	}

	// if
	if len(participants) == 0 {
		cue.Controller.log.Notice("This channel (%d) doesnt have any participant but we are trying to send an event to it, please investigate", cue.Channel.Id)
		return nil
	}

	for _, accountId := range participants {
		if !cue.isEligibleForBroadcasting(accountId) {
			cue.Controller.log.Debug("not sending event to the creator of this operation %s", cue.EventType)
			continue
		}

		cp := models.NewChannelParticipant()
		cp.ChannelId = cue.Channel.Id
		cp.AccountId = accountId
		if err := cp.FetchParticipant(); err != nil {
			cue.Controller.log.Error("Err: %s, skipping account %d", err.Error(), accountId)
			return nil
		}
		cue.ChannelParticipant = cp

		err := cue.sendForParticipant()
		if err != nil {
			return err
		}

	}

	return nil
}

func (cue *channelUpdatedEvent) isEligibleForBroadcasting(accountId int64) bool {
	// if parent message is empty do send
	// realtime  updates to the client
	if cue.ParentChannelMessage == nil {
		return true
	}

	// if we are gonna send this notification to topic channel
	// do not send to initiator
	if cue.Channel.TypeConstant == models.Channel_TYPE_TOPIC {
		if cue.ParentChannelMessage.AccountId == accountId {
			return false
		}
	}

	// if reply is not set do send this event
	if cue.ReplyChannelMessage == nil {
		return true
	}

	// if parent message's crateor is account
	// dont send it
	// this has introduced some bugs to system, like if someone
	// comments to my post(i also pinned it)
	// i wasnt getting any notification
	// if cue.ParentChannelMessage.AccountId == accountId {
	// 	return false
	// }

	// if reply message's crateor is account
	// dont send it
	if cue.ReplyChannelMessage.AccountId == accountId {
		return false
	}

	return true
}

func (cue *channelUpdatedEvent) validateChannelUpdatedEvents() error {
	// channel shouldnt be nil
	if cue.Channel == nil {
		return fmt.Errorf("Channel is nil")
	}

	// channel id should be set inorder to send event to the channel
	if cue.Channel.Id == 0 {
		return fmt.Errorf("Channel id is not set")
	}

	// filter group events
	// do not send any -updated- event to group channels
	if cue.Channel.TypeConstant == models.Channel_TYPE_GROUP {
		return fmt.Errorf("Not sending group (%s) event", cue.Channel.GroupName)
	}

	// do not send comment events to topic channels
	// other than topic channel, channels persist their messages as replies
	if cue.Channel.TypeConstant != models.Channel_TYPE_TOPIC {
		return nil
	}

	// if we dont have a parent message it means this is a post addition/creation
	if cue.ParentChannelMessage == nil {
		return nil
	}

	// send only post operations the the client
	if cue.ParentChannelMessage.TypeConstant != models.ChannelMessage_TYPE_POST {
		return fmt.Errorf("Not sending non-post (%s) event to topic channel",
			cue.ParentChannelMessage.TypeConstant,
		)
	}

	return nil
}

func (cue *channelUpdatedEvent) sendForParticipant() error {
	if cue.ChannelParticipant == nil {
		return errors.New("Channel Participant is nil")
	}

	count, err := cue.calculateUnreadItemCount()
	if err != nil {
		cue.Controller.log.Notice("Error happened, setting unread count to 0 %s", err.Error())
		count = 0
	}

	cue.UnreadCount = count

	err = cue.Controller.sendNotification(cue.ChannelParticipant.AccountId, ChannelUpdateEventName, cue)
	if err != nil {
		cue.Controller.log.Error(err.Error())
	}

	return nil
}

func (cue *channelUpdatedEvent) calculateUnreadItemCount() (int, error) {
	if cue.ParentChannelMessage == nil {
		return models.NewChannelMessageList().UnreadCount(cue.ChannelParticipant)
	}

	// for topic channel unread count will be calculated from unread post count
	if cue.Channel.TypeConstant == models.Channel_TYPE_TOPIC {
		return models.NewChannelMessageList().UnreadCount(cue.ChannelParticipant)
	}

	// for private messages calculate the unread reply count
	if cue.Channel.TypeConstant == models.Channel_TYPE_PRIVATE_MESSAGE {
		count, err := models.NewMessageReply().UnreadCount(cue.ParentChannelMessage.Id, cue.ChannelParticipant.LastSeenAt)
		if err != nil {
			return 0, err
		}

		// if unread count is 0
		// set it to 1 for now
		// because we want to show a notification with a sign
		if count == 0 {
			count = 1
		}

		return count, nil
	}

	cue.Controller.log.Critical("Calculating unread count shouldnt fall here")
	return 0, nil
}
<commit_msg>Social: for pinned posts calculate unread count from message's added at into that channel<commit_after>package realtime

import (
	"errors"
	"fmt"
	"socialapi/models"
)

type channelUpdatedEventType string

var (
	channelUpdatedEventMessageAddedToChannel     channelUpdatedEventType = "MessageAddedToChannel"
	channelUpdatedEventMessageRemovedFromChannel channelUpdatedEventType = "MessageRemovedFromChannel"
	channelUpdatedEventMessageUpdatedAtChannel   channelUpdatedEventType = "MessageListUpdated"
	channelUpdatedEventReplyAdded                channelUpdatedEventType = "ReplyAdded"
	channelUpdatedEventReplyRemoved              channelUpdatedEventType = "ReplyRemoved"
	channelUpdatedEventChannelParticipantUpdated channelUpdatedEventType = "ParticipantUpdated"
)

type channelUpdatedEvent struct {
	Controller           *Controller                `json:"-"`
	Channel              *models.Channel            `json:"channel"`
	ParentChannelMessage *models.ChannelMessage     `json:"channelMessage"`
	ReplyChannelMessage  *models.ChannelMessage     `json:"-"`
	EventType            channelUpdatedEventType    `json:"event"`
	ChannelParticipant   *models.ChannelParticipant `json:"-"`
	UnreadCount          int                        `json:"unreadCount"`
}

// sendChannelUpdatedEvent sends channel updated events
func (cue *channelUpdatedEvent) send() error {
	cue.Controller.log.Debug("sending channel update event %+v", cue)

	if err := cue.validateChannelUpdatedEvents(); err != nil {
		cue.Controller.log.Error(err.Error())
		// this is not an error actually
		return nil
	}

	// fetch all participants of related channel
	// if you ask why we are not sending those messaages to the channel's channel
	// instead of sending events as notifications?, because we are also sending
	// unread counts of the related channel's messages by the notifiee
	participants, err := cue.Channel.FetchParticipantIds()
	if err != nil {
		cue.Controller.log.Error("Error occured while fetching participants %s", err.Error())
		return err
	}

	// if
	if len(participants) == 0 {
		cue.Controller.log.Notice("This channel (%d) doesnt have any participant but we are trying to send an event to it, please investigate", cue.Channel.Id)
		return nil
	}

	for _, accountId := range participants {
		if !cue.isEligibleForBroadcasting(accountId) {
			cue.Controller.log.Debug("not sending event to the creator of this operation %s", cue.EventType)
			continue
		}

		cp := models.NewChannelParticipant()
		cp.ChannelId = cue.Channel.Id
		cp.AccountId = accountId
		if err := cp.FetchParticipant(); err != nil {
			cue.Controller.log.Error("Err: %s, skipping account %d", err.Error(), accountId)
			return nil
		}
		cue.ChannelParticipant = cp

		err := cue.sendForParticipant()
		if err != nil {
			return err
		}

	}

	return nil
}

func (cue *channelUpdatedEvent) isEligibleForBroadcasting(accountId int64) bool {
	// if parent message is empty do send
	// realtime  updates to the client
	if cue.ParentChannelMessage == nil {
		return true
	}

	// if we are gonna send this notification to topic channel
	// do not send to initiator
	if cue.Channel.TypeConstant == models.Channel_TYPE_TOPIC {
		if cue.ParentChannelMessage.AccountId == accountId {
			return false
		}
	}

	// if reply is not set do send this event
	if cue.ReplyChannelMessage == nil {
		return true
	}

	// if parent message's crateor is account
	// dont send it
	// this has introduced some bugs to system, like if someone
	// comments to my post(i also pinned it)
	// i wasnt getting any notification
	// if cue.ParentChannelMessage.AccountId == accountId {
	// 	return false
	// }

	// if reply message's crateor is account
	// dont send it
	if cue.ReplyChannelMessage.AccountId == accountId {
		return false
	}

	return true
}

func (cue *channelUpdatedEvent) validateChannelUpdatedEvents() error {
	// channel shouldnt be nil
	if cue.Channel == nil {
		return fmt.Errorf("Channel is nil")
	}

	// channel id should be set inorder to send event to the channel
	if cue.Channel.Id == 0 {
		return fmt.Errorf("Channel id is not set")
	}

	// filter group events
	// do not send any -updated- event to group channels
	if cue.Channel.TypeConstant == models.Channel_TYPE_GROUP {
		return fmt.Errorf("Not sending group (%s) event", cue.Channel.GroupName)
	}

	// do not send comment events to topic channels
	// other than topic channel, channels persist their messages as replies
	if cue.Channel.TypeConstant != models.Channel_TYPE_TOPIC {
		return nil
	}

	// if we dont have a parent message it means this is a post addition/creation
	if cue.ParentChannelMessage == nil {
		return nil
	}

	// send only post operations the the client
	if cue.ParentChannelMessage.TypeConstant != models.ChannelMessage_TYPE_POST {
		return fmt.Errorf("Not sending non-post (%s) event to topic channel",
			cue.ParentChannelMessage.TypeConstant,
		)
	}

	return nil
}

func (cue *channelUpdatedEvent) sendForParticipant() error {
	if cue.ChannelParticipant == nil {
		return errors.New("Channel Participant is nil")
	}

	count, err := cue.calculateUnreadItemCount()
	if err != nil {
		cue.Controller.log.Notice("Error happened, setting unread count to 0 %s", err.Error())
		count = 0
	}

	cue.UnreadCount = count

	err = cue.Controller.sendNotification(cue.ChannelParticipant.AccountId, ChannelUpdateEventName, cue)
	if err != nil {
		cue.Controller.log.Error(err.Error())
	}

	return nil
}

func (cue *channelUpdatedEvent) calculateUnreadItemCount() (int, error) {
	if cue.ParentChannelMessage == nil {
		return models.NewChannelMessageList().UnreadCount(cue.ChannelParticipant)
	}

	// for topic channel unread count will be calculated from unread post count
	if cue.Channel.TypeConstant == models.Channel_TYPE_TOPIC {
		return models.NewChannelMessageList().UnreadCount(cue.ChannelParticipant)
	}

	// from this poin we need parent message

	// for pinned posts calculate unread count from message's added at into that channel
	if cue.Channel.TypeConstant == models.Channel_TYPE_PINNED_ACTIVITY {
		cml, err := cue.Channel.FetchMessageList(cue.ParentChannelMessage.Id)
		if err != nil {
			return 0, err
		}

		// for pinned posts we are calculating unread count from reviseddAt of the
		// regarding channel message list, since only participant for the channel
		// is the owner and we cant use channel_participant for unread counts
		// on the other hand messages should have their own unread count
		// we are specialcasing the pinned posts here
		return models.NewMessageReply().UnreadCount(cml.MessageId, cml.RevisedAt)
	}

	// for private messages calculate the unread reply count
	if cue.Channel.TypeConstant == models.Channel_TYPE_PRIVATE_MESSAGE {
		count, err := models.NewMessageReply().UnreadCount(cue.ParentChannelMessage.Id, cue.ChannelParticipant.LastSeenAt)
		if err != nil {
			return 0, err
		}

		// if unread count is 0
		// set it to 1 for now
		// because we want to show a notification with a sign
		if count == 0 {
			count = 1
		}

		return count, nil
	}

	cue.Controller.log.Critical("Calculating unread count shouldnt fall here")
	return 0, nil
}
<|endoftext|>


<commit_before>package jpush

import (
	"encoding/json"
	"errors"
	"github.com/wuyongzhi/gopush/utils"
	"io/ioutil"
	"net/http"
	_ "net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
	"crypto/md5"
	"encoding/hex"
)

const JPushServerUrl string = "http://api.jpush.cn:8800/v2/push"
const JPushServerUrlSsl string = "https://api.jpush.cn:443/v2/push"

type Request struct {
	url.Values
}

type NotifyMessage struct {
	BuilderId int		`json:"n_builder_id"`
	Title string		`json:"n_title"`
	Content string		`json:"n_content"`
	Extras string		`json:"n_extras"`
}

type CustomMessage struct {
	Message string		`json:"message"`
	ContentType int    	`json:"content_type"`
	Title string		`json:"title"`
	Extras string		`json:"extras"`
}

type JPushMsgId interface {}

var InvalidMsgId JPushMsgId = nil

type Response struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	MsgId   JPushMsgId `json:"msg_id"`
}

type Response2 struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`

}

func NewRequest() *Request {
	m := Request{}
	m.Values = make(map[string][]string, 8)
	return &m
}

func (r *Response) IsOk() bool {
	return r.ErrCode == 0
}

func (r *Response) IsFailed() bool {
	return r.ErrCode != 0
}

func (m *Request) Set(key, value string){
	m.Values.Set(key, value)
}

func (m *Request) SetInt(key string, value int){
	m.Set(key, strconv.Itoa(value))
}

func (m *Request) SendNo(sendno int){
	m.SetInt("sendno", sendno)
}

func (m *Request) AppKey(app_key string) {
	m.Set("app_key", app_key)
}

const (
	ReceiverTypeTag            int = 2
	ReceiverTypeAlias              = 3
	ReceiverTypeBoardcast          = 4
	ReceiverTypeRegistrationID     = 5
)

const (
	MsgTypeNotify = 1
	MsgTypeCustom = 2
)

//	可以是以下值:
//		ReceiverTypeAlias
// 		ReceiverTypeTag
// 		ReceiverTypeBoardcast
// 		ReceiverTypeRegistrationID
func (m *Request) ReceiverType(receiver_type int)  {
	m.SetInt("receiver_type", receiver_type)
}

func (m *Request) ReceiverValue(receiver_values ...string) {
	m.Set("receiver_value", strings.Join(receiver_values, ","))
}

//允许传递认证码自行认证，也可以在调用Send 时，传递有效的 master_secret 参数来生成认证码
func (m *Request) VerificationCode(verification_code string)  {
	m.Set("verification_code", verification_code)
}

//可以是以下值：
//
// 	MsgTypeNotify
// 	MsgTypeCustom
func (m *Request) MsgType(msg_type int)  {
	m.SetInt("msg_type", msg_type)
}

func (m *Request) MessageNotify(n_builder_id int, n_title, n_content, n_extras string) {
	msg := NotifyMessage{n_builder_id, n_title, n_content, n_extras}
	bytes, _ := json.Marshal(msg)
	m.Set("msg_content", string(bytes))
	m.SetInt("msg_type", MsgTypeNotify)
}

func (m *Request) MessageCustom(message, title, extras string, contentType int) {
	msg := CustomMessage{
		Message: message,
		Title: title,
		Extras: extras,
		ContentType: contentType,
	}
	bytes, _ := json.Marshal(msg)
	m.Set("msg_content", string(bytes))
	m.SetInt("msg_type", MsgTypeCustom)
}

func (m *Request) SendDescription(send_description string)  {
	m.Set("send_description", send_description)
}

//按可变参数，挨个传递“平台”，方法会用逗号将它们拼起来
func (m *Request) Platform(platforms ...string)  {
	m.Set("platform", strings.Join(platforms, ","))
}

// 仅IOS  适用 0 开发环境；1 生产环境
func (m *Request) APNSProduction(apns_production int)  {
	m.SetInt("apns_production", apns_production)
}

func (m *Request) TimeToLive(time_to_live int)  {
	m.SetInt("time_to_live", time_to_live)
}

func (m *Request) OverrideMsgId(override_msg_id string)  {
	m.Set("override_msg_id", override_msg_id)
}

func (m *Request) Sign(master_secret string)  {
	src := m.Values.Get("sendno") + m.Values.Get("receiver_type") + m.Values.Get("receiver_value") + master_secret
//	fmt.Println(src)
	sum := md5.Sum([]byte(src))
	verification_code := hex.EncodeToString(sum[:])
	m.Values.Set("verification_code", verification_code)

}

func (m *Request) send(url string) (*Response, error) {

	resp, err := defaultHttpClient.PostForm(url, m.Values)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(strconv.Itoa(resp.StatusCode) + resp.Status)
	}

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var jpushResponse Response

	//	responseContent := string(bytes)
	err = json.Unmarshal(bytes, &jpushResponse)
	if err != nil {
		return nil, errors.New(err.Error() + " response: \n" + string(bytes))
	}

	// 如果失败，转换为 go 的 error
	if jpushResponse.IsFailed() {
		return &jpushResponse, errors.New(strconv.Itoa(jpushResponse.ErrCode) + ", " + jpushResponse.ErrMsg)
	}

	return &jpushResponse, nil

}

// 使用 http 协议
func (m *Request) Send() (*Response, error) {
	return m.send(JPushServerUrl)
}

// 使用 https 协议
func (m *Request) SendSecure() (*Response, error) {
	return m.send(JPushServerUrlSsl)
}

var defaultHttpClient *utils.HttpClient

func init() {
	timeout, _ := time.ParseDuration("10s")
	defaultHttpClient = utils.NewHttpClient(20, timeout, timeout, false)
	//defaultHttpClient.
}
<commit_msg>默认60秒超时<commit_after>package jpush

import (
	"encoding/json"
	"errors"
	"github.com/wuyongzhi/gopush/utils"
	"io/ioutil"
	"net/http"
	_ "net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
	"crypto/md5"
	"encoding/hex"
)

const JPushServerUrl string = "http://api.jpush.cn:8800/v2/push"
const JPushServerUrlSsl string = "https://api.jpush.cn:443/v2/push"

type Request struct {
	url.Values
}

type NotifyMessage struct {
	BuilderId int		`json:"n_builder_id"`
	Title string		`json:"n_title"`
	Content string		`json:"n_content"`
	Extras string		`json:"n_extras"`
}

type CustomMessage struct {
	Message string		`json:"message"`
	ContentType int    	`json:"content_type"`
	Title string		`json:"title"`
	Extras string		`json:"extras"`
}

type JPushMsgId interface {}

var InvalidMsgId JPushMsgId = nil

type Response struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	MsgId   JPushMsgId `json:"msg_id"`
}

type Response2 struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`

}

func NewRequest() *Request {
	m := Request{}
	m.Values = make(map[string][]string, 8)
	return &m
}

func (r *Response) IsOk() bool {
	return r.ErrCode == 0
}

func (r *Response) IsFailed() bool {
	return r.ErrCode != 0
}

func (m *Request) Set(key, value string){
	m.Values.Set(key, value)
}

func (m *Request) SetInt(key string, value int){
	m.Set(key, strconv.Itoa(value))
}

func (m *Request) SendNo(sendno int){
	m.SetInt("sendno", sendno)
}

func (m *Request) AppKey(app_key string) {
	m.Set("app_key", app_key)
}

const (
	ReceiverTypeTag            int = 2
	ReceiverTypeAlias              = 3
	ReceiverTypeBoardcast          = 4
	ReceiverTypeRegistrationID     = 5
)

const (
	MsgTypeNotify = 1
	MsgTypeCustom = 2
)

//	可以是以下值:
//		ReceiverTypeAlias
// 		ReceiverTypeTag
// 		ReceiverTypeBoardcast
// 		ReceiverTypeRegistrationID
func (m *Request) ReceiverType(receiver_type int)  {
	m.SetInt("receiver_type", receiver_type)
}

func (m *Request) ReceiverValue(receiver_values ...string) {
	m.Set("receiver_value", strings.Join(receiver_values, ","))
}

//允许传递认证码自行认证，也可以在调用Send 时，传递有效的 master_secret 参数来生成认证码
func (m *Request) VerificationCode(verification_code string)  {
	m.Set("verification_code", verification_code)
}

//可以是以下值：
//
// 	MsgTypeNotify
// 	MsgTypeCustom
func (m *Request) MsgType(msg_type int)  {
	m.SetInt("msg_type", msg_type)
}

func (m *Request) MessageNotify(n_builder_id int, n_title, n_content, n_extras string) {
	msg := NotifyMessage{n_builder_id, n_title, n_content, n_extras}
	bytes, _ := json.Marshal(msg)
	m.Set("msg_content", string(bytes))
	m.SetInt("msg_type", MsgTypeNotify)
}

func (m *Request) MessageCustom(message, title, extras string, contentType int) {
	msg := CustomMessage{
		Message: message,
		Title: title,
		Extras: extras,
		ContentType: contentType,
	}
	bytes, _ := json.Marshal(msg)
	m.Set("msg_content", string(bytes))
	m.SetInt("msg_type", MsgTypeCustom)
}

func (m *Request) SendDescription(send_description string)  {
	m.Set("send_description", send_description)
}

//按可变参数，挨个传递“平台”，方法会用逗号将它们拼起来
func (m *Request) Platform(platforms ...string)  {
	m.Set("platform", strings.Join(platforms, ","))
}

// 仅IOS  适用 0 开发环境；1 生产环境
func (m *Request) APNSProduction(apns_production int)  {
	m.SetInt("apns_production", apns_production)
}

func (m *Request) TimeToLive(time_to_live int)  {
	m.SetInt("time_to_live", time_to_live)
}

func (m *Request) OverrideMsgId(override_msg_id string)  {
	m.Set("override_msg_id", override_msg_id)
}

func (m *Request) Sign(master_secret string)  {
	src := m.Values.Get("sendno") + m.Values.Get("receiver_type") + m.Values.Get("receiver_value") + master_secret
//	fmt.Println(src)
	sum := md5.Sum([]byte(src))
	verification_code := hex.EncodeToString(sum[:])
	m.Values.Set("verification_code", verification_code)

}

func (m *Request) send(url string) (*Response, error) {

	resp, err := defaultHttpClient.PostForm(url, m.Values)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(strconv.Itoa(resp.StatusCode) + resp.Status)
	}

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var jpushResponse Response

	//	responseContent := string(bytes)
	err = json.Unmarshal(bytes, &jpushResponse)
	if err != nil {
		return nil, errors.New(err.Error() + " response: \n" + string(bytes))
	}

	// 如果失败，转换为 go 的 error
	if jpushResponse.IsFailed() {
		return &jpushResponse, errors.New(strconv.Itoa(jpushResponse.ErrCode) + ", " + jpushResponse.ErrMsg)
	}

	return &jpushResponse, nil

}

// 使用 http 协议
func (m *Request) Send() (*Response, error) {
	return m.send(JPushServerUrl)
}

// 使用 https 协议
func (m *Request) SendSecure() (*Response, error) {
	return m.send(JPushServerUrlSsl)
}

var defaultHttpClient *utils.HttpClient

func init() {
	timeout, _ := time.ParseDuration("60s")
	defaultHttpClient = utils.NewHttpClient(20, timeout, timeout, false)
	//defaultHttpClient.
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"go/parser"
	"go/types"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "%s ./pkg/foo > tests/clone/generated/foo_test.go\n", os.Args[0])
		os.Exit(1)
	}
	infos := extractInfos(os.Args[1:])
	generateTests(infos)
}

func extractInfos(pkgs []string) []info {
	infos := make([]info, 0)
	docIface := getDocIface()

	for _, pkgPath := range pkgs {
		pkg, err := pkgInfoFromPath(pkgPath)
		if err != nil {
			panic(err)
		}

		in := info{
			PkgName: pkg.Name(),
			PkgPath: pkg.Path(),
			Structs: make(map[string][]mutableField),
		}
		scope := pkg.Scope()
		for _, name := range scope.Names() {
			obj := scope.Lookup(name)
			s, ok := obj.Type().Underlying().(*types.Struct)
			if !ok {
				continue
			}
			ptr := types.NewPointer(obj.Type())
			// FIXME implements returns false for intents.Intent but it should
			// return true, find why!
			// implements := types.Implements(ptr.Underlying(), docIface)
			f, g := types.MissingMethod(ptr.Underlying(), docIface, true)
			if f != nil && !g {
				continue
			}
			fields := make([]mutableField, 0)
			for i := 0; i < s.NumFields(); i++ {
				field := s.Field(i)
				// fmt.Printf(" - %d. %s - %s\n", i, field.Name(), field.Type())
				switch t := field.Type().(type) {
				case (*types.Slice):
					fields = append(fields, &sliceField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Map):
					fields = append(fields, &mapField{
						Name:  field.Name(),
						Key:   generatorForType(t.Key()),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Named):
					named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
					switch named {
					case "time.Time", "time.Duration":
						// These structs are known to be safe
					default:
						panic(fmt.Errorf("Unknown named type: %s", named))
					}
				case (*types.Interface):
					fmt.Fprintf(os.Stderr, "Warning: cannot check interfaces: %s.%s -> %s\n",
						pkg.Name(), name, field)
				case (*types.Basic):
					// Basic types are immutables
				default:
					panic(fmt.Errorf("Unknown type: %#v", field.Type()))
				}
			}
			if len(fields) > 0 {
				in.Structs[name] = fields
			}
		}
		if len(in.Structs) > 0 {
			infos = append(infos, in)
		}
	}
	return infos
}

func generateTests(infos []info) {
	fmt.Printf(`// Generated tests for Clone(). Do not manually edit!
package clone

import (
	"testing"
`)
	for _, info := range infos {
		fmt.Printf("\t\"%s\"\n", info.PkgPath)
	}
	fmt.Printf(")\n\n")

	for _, info := range infos {
		fmt.Printf("func Test%s(t *testing.T) {\n", strings.Title(info.PkgName))
		for name, fields := range info.Structs {
			v := strings.ToLower(name)
			fmt.Printf("\t%sA := &%s.%s{}\n", v, info.PkgName, name)
			for _, field := range fields {
				field.Initialize(v)
			}
			ptr := "*"
			if name == "JSONDoc" {
				ptr = ""
			}
			fmt.Printf("\t%sB := %sA.Clone().(%s%s.%s)\n", v, v, ptr, info.PkgName, name)
			for _, field := range fields {
				field.Reassign(v)
				field.Compare(v)
				fmt.Printf("\t\tt.Fatalf(\"Error for clone %s.%s -> %s\")\n\t}\n", info.PkgName, name, field)
			}
		}
		fmt.Printf("}\n\n")
	}
}

type info struct {
	PkgName string
	PkgPath string
	Structs map[string][]mutableField
}

type mutableField interface {
	String() string
	Initialize(v string)
	Reassign(v string)
	Compare(v string)
}

type sliceField struct {
	Name  string
	Value generator
}

func (f *sliceField) String() string { return f.Name }

func (f *sliceField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = []%s{%s}\n", v, f.Name, f.Value.Type, f.Value.Initial)
}
func (f *sliceField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[0] = %s\n", v, f.Name, f.Value.Altered)
}
func (f *sliceField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[0] != %s {\n", v, f.Name, f.Value.Initial)
}

type mapField struct {
	Name  string
	Key   generator
	Value generator
}

func (f *mapField) String() string { return f.Name }

func (f *mapField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s\n", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = map[%s]%s{%s: %s}\n", v, f.Name, f.Key.Type, f.Value.Type, f.Key.Key, f.Value.Initial)
}
func (f *mapField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[%s] = %s\n", v, f.Name, f.Key.Key, f.Value.Altered)
}
func (f *mapField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[%s] != %s {\n", v, f.Name, f.Key.Key, f.Value.Initial)
}

func generatorForType(typ types.Type) generator {
	switch t := typ.(type) {
	case (*types.Basic):
		switch t.Name() {
		case "string":
			return stringGenerator
		default:
			panic(fmt.Errorf("Unknown basic type: %s", t.Name()))
		}
	case (*types.Interface):
		if t.Empty() {
			return emptyInterfaceGenerator
		}
	}
	//return stringGenerator
	panic(fmt.Errorf("Unknown generator type: %#v", typ))
}

type generator struct {
	Type    string
	Key     string
	Initial string
	Altered string
	Warning string
}

var stringGenerator = generator{
	Type:    "string",
	Key:     `"foo"`,
	Initial: `"bar"`,
	Altered: `"baz"`,
}

var emptyInterfaceGenerator = generator{
	Type:    "interface{}",
	Key:     "0",
	Initial: "1",
	Altered: "2",
	Warning: "interface{} can contain nested data!",
}

// getDocIface returns the couchdb.Doc interface
func getDocIface() *types.Interface {
	couchPkg := "github.com/cozy/cozy-stack/pkg/couchdb"
	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(couchPkg)
	lprog, err := conf.Load()
	if err != nil {
		panic(err)
	}
	scope := lprog.Package(couchPkg).Pkg.Scope()
	return scope.Lookup("Doc").Type().Underlying().(*types.Interface)
}

// pkgInfoFromPath returns information about the package
// Taken from https://github.com/matryer/moq
func pkgInfoFromPath(src string) (*types.Package, error) {
	abs, err := filepath.Abs(src)
	if err != nil {
		return nil, err
	}
	pkgFull := stripGopath(abs)

	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(pkgFull)
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	pkgInfo := lprog.Package(pkgFull)
	if pkgInfo == nil {
		return nil, errors.New("package was nil")
	}

	return pkgInfo.Pkg, nil
}

// stripGopath takes the directory to a package and remove the gopath to get the
// canonical package name.
// Taken from https://github.com/ernesto-jimenez/gogen
func stripGopath(p string) string {
	for _, gopath := range gopaths() {
		p = strings.TrimPrefix(p, path.Join(gopath, "src")+"/")
	}
	return p
}

func gopaths() []string {
	return strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
}
<commit_msg>Add clone test for pointer to struct<commit_after>package main

import (
	"errors"
	"fmt"
	"go/parser"
	"go/types"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "%s ./pkg/foo > tests/clone/generated/foo_test.go\n", os.Args[0])
		os.Exit(1)
	}
	infos := extractInfos(os.Args[1:])
	generateTests(infos)
}

func extractInfos(pkgs []string) []info {
	infos := make([]info, 0)
	docIface := getDocIface()

	for _, pkgPath := range pkgs {
		pkg, err := pkgInfoFromPath(pkgPath)
		if err != nil {
			panic(err)
		}

		in := info{
			PkgName: pkg.Name(),
			PkgPath: pkg.Path(),
			Structs: make(map[string][]mutableField),
		}
		scope := pkg.Scope()
		for _, name := range scope.Names() {
			obj := scope.Lookup(name)
			s, ok := obj.Type().Underlying().(*types.Struct)
			if !ok {
				continue
			}
			ptr := types.NewPointer(obj.Type())
			// FIXME implements returns false for intents.Intent but it should
			// return true, find why!
			// implements := types.Implements(ptr.Underlying(), docIface)
			f, g := types.MissingMethod(ptr.Underlying(), docIface, true)
			if f != nil && !g {
				continue
			}
			fields := make([]mutableField, 0)
			for i := 0; i < s.NumFields(); i++ {
				field := s.Field(i)
				// fmt.Printf(" - %d. %s - %s\n", i, field.Name(), field.Type())
				switch t := field.Type().(type) {
				case (*types.Slice):
					fields = append(fields, &sliceField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Map):
					fields = append(fields, &mapField{
						Name:  field.Name(),
						Key:   generatorForType(t.Key()),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Named):
					named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
					switch named {
					case "time.Time", "time.Duration":
						// These structs are known to be safe
					default:
						panic(fmt.Errorf("Unknown named type: %s", named))
					}
				case (*types.Interface):
					fmt.Fprintf(os.Stderr, "Warning: cannot check interfaces: %s.%s -> %s\n",
						pkg.Name(), name, field)
				case (*types.Pointer):
					fields = append(fields, &ptrField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Basic):
					// Basic types are immutables
				default:
					panic(fmt.Errorf("Unknown type: %#v", field.Type()))
				}
			}
			if len(fields) > 0 {
				in.Structs[name] = fields
			}
		}
		if len(in.Structs) > 0 {
			infos = append(infos, in)
		}
	}
	return infos
}

func generateTests(infos []info) {
	fmt.Printf(`// Generated tests for Clone(). Do not manually edit!
package clone

import (
	"testing"
`)
	for _, info := range infos {
		fmt.Printf("\t\"%s\"\n", info.PkgPath)
	}
	fmt.Printf(")\n\n")

	for _, info := range infos {
		fmt.Printf("func Test%s(t *testing.T) {\n", strings.Title(info.PkgName))
		for name, fields := range info.Structs {
			v := strings.ToLower(name)
			fmt.Printf("\t%sA := &%s.%s{}\n", v, info.PkgName, name)
			for _, field := range fields {
				field.Initialize(v)
			}
			ptr := "*"
			if name == "JSONDoc" {
				ptr = ""
			}
			fmt.Printf("\t%sB := %sA.Clone().(%s%s.%s)\n", v, v, ptr, info.PkgName, name)
			for _, field := range fields {
				field.Reassign(v)
				field.Compare(v)
				fmt.Printf("\t\tt.Fatalf(\"Error for clone %s.%s -> %s\")\n\t}\n", info.PkgName, name, field)
			}
		}
		fmt.Printf("}\n\n")
	}
}

type info struct {
	PkgName string
	PkgPath string
	Structs map[string][]mutableField
}

type mutableField interface {
	String() string
	Initialize(v string)
	Reassign(v string)
	Compare(v string)
}

type sliceField struct {
	Name  string
	Value generator
}

func (f *sliceField) String() string { return f.Name }

func (f *sliceField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = []%s{%s}\n", v, f.Name, f.Value.Type, f.Value.Initial)
}
func (f *sliceField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[0]%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *sliceField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[0]%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

type mapField struct {
	Name  string
	Key   generator
	Value generator
}

func (f *mapField) String() string { return f.Name }

func (f *mapField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s\n", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = map[%s]%s{%s: %s}\n", v, f.Name, f.Key.Type, f.Value.Type, f.Key.Key, f.Value.Initial)
}
func (f *mapField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[%s]%s = %s\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.Altered)
}
func (f *mapField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[%s]%s != %s {\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.SubValue)
}

type ptrField struct {
	Name  string
	Value generator
}

func (f *ptrField) String() string { return f.Name }

func (f *ptrField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = &%s\n", v, f.Name, f.Value.Initial)
}
func (f *ptrField) Reassign(v string) {
	fmt.Printf("\t%sA.%s%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *ptrField) Compare(v string) {
	fmt.Printf("\tif %sB.%s%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

func generatorForType(typ types.Type) generator {
	switch t := typ.(type) {
	case (*types.Basic):
		switch t.Name() {
		case "string":
			return stringGenerator
		default:
			panic(fmt.Errorf("Unknown basic type: %s", t.Name()))
		}
	case (*types.Interface):
		if t.Empty() {
			return emptyInterfaceGenerator
		}
	case (*types.Named):
		if s, ok := t.Obj().Type().Underlying().(*types.Struct); ok {
			named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
			return structGenerator(named, s)
		}
	}
	panic(fmt.Errorf("Unknown generator type: %#v", typ))
}

type generator struct {
	Type     string
	Key      string
	Initial  string
	Altered  string
	Warning  string
	SubKey   string
	SubValue string
}

var stringGenerator = generator{
	Type:     "string",
	Key:      `"foo"`,
	Initial:  `"bar"`,
	Altered:  `"baz"`,
	SubValue: `"bar"`,
}

var emptyInterfaceGenerator = generator{
	Type:     "interface{}",
	Key:      "0",
	Initial:  "1",
	Altered:  "2",
	SubValue: "1",
	Warning:  "interface{} can contain nested data!",
}

func structGenerator(name string, s *types.Struct) generator {
	f := s.Field(0)
	g := generatorForType(f.Type())
	return generator{
		Type:     "&ptr",
		Initial:  fmt.Sprintf("%s{%s: %s}", name, f.Name(), g.Initial),
		Altered:  g.Altered,
		SubKey:   "." + f.Name(),
		SubValue: g.SubValue,
	}
}

// getDocIface returns the couchdb.Doc interface
func getDocIface() *types.Interface {
	couchPkg := "github.com/cozy/cozy-stack/pkg/couchdb"
	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(couchPkg)
	lprog, err := conf.Load()
	if err != nil {
		panic(err)
	}
	scope := lprog.Package(couchPkg).Pkg.Scope()
	return scope.Lookup("Doc").Type().Underlying().(*types.Interface)
}

// pkgInfoFromPath returns information about the package
// Taken from https://github.com/matryer/moq
func pkgInfoFromPath(src string) (*types.Package, error) {
	abs, err := filepath.Abs(src)
	if err != nil {
		return nil, err
	}
	pkgFull := stripGopath(abs)

	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(pkgFull)
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	pkgInfo := lprog.Package(pkgFull)
	if pkgInfo == nil {
		return nil, errors.New("package was nil")
	}

	return pkgInfo.Pkg, nil
}

// stripGopath takes the directory to a package and remove the gopath to get the
// canonical package name.
// Taken from https://github.com/ernesto-jimenez/gogen
func stripGopath(p string) string {
	for _, gopath := range gopaths() {
		p = strings.TrimPrefix(p, path.Join(gopath, "src")+"/")
	}
	return p
}

func gopaths() []string {
	return strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
}
<|endoftext|>


<commit_before>package etw

// Channel represents the ETW logging channel that is used. It can be used by
// event consumers to give an event special treatment.
type Channel uint8

const (
	// ChannelTraceLogging is the default channel for TraceLogging events. It is
	// not required to be used for TraceLogging, but will prevent decoding
	// issues for these events on older operating systems.
	ChannelTraceLogging Channel = 11
)

// Level represents the ETW logging level. There are several predefined levels
// that are commonly used, but technically anything from 0-255 is allowed.
// Lower levels indicate more important events, and 0 indicates an event that
// will always be collected.
type Level uint8

// Predefined ETW log levels.
const (
	LevelAlways Level = iota
	LevelCritical
	LevelError
	LevelWarning
	LevelInfo
	LevelVerbose
)

// Event represents a single ETW event. It can have field metadata and data
// added to it, and then be logged via a provider to actually send it to ETW.
type Event struct {
	Descriptor *EventDescriptor
	Metadata   *EventMetadata
	Data       *EventData
}

// NewEvent returns a new instance of an event object.
func NewEvent(name string, descriptor *EventDescriptor) *Event {
	return &Event{
		Descriptor: descriptor,
		Metadata:   NewEventMetadata(name),
		Data:       &EventData{},
	}
}

// EventDescriptor represents various metadata for an ETW event.
type EventDescriptor struct {
	id      uint16
	version uint8
	Channel Channel
	Level   Level
	Opcode  uint8
	Task    uint16
	Keyword uint64
}

// NewEventDescriptor returns an EventDescriptor initialized for use with
// TraceLogging.
func NewEventDescriptor() *EventDescriptor {
	// Standard TraceLogging events default to the TraceLogging channel, and
	// verbose level.
	return &EventDescriptor{
		id:      0,
		version: 0,
		Channel: ChannelTraceLogging,
		Level:   LevelVerbose,
		Opcode:  0,
		Task:    0,
		Keyword: 0,
	}
}

// Identity returns the identity of the event. If the identity is not 0, it
// should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant.
func (ed *EventDescriptor) Identity() uint32 {
	return (uint32(ed.version) << 16) & uint32(ed.id)
}

// SetIdentity sets the identity of the event. If the identity is not 0, it
// should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant.
func (ed *EventDescriptor) SetIdentity(identity uint32) {
	ed.id = uint16(identity)
	ed.version = uint8(identity >> 16)
}
<commit_msg>Update pkg/etw/event.go<commit_after>package etw

// Channel represents the ETW logging channel that is used. It can be used by
// event consumers to give an event special treatment.
type Channel uint8

const (
	// ChannelTraceLogging is the default channel for TraceLogging events. It is
	// not required to be used for TraceLogging, but will prevent decoding
	// issues for these events on older operating systems.
	ChannelTraceLogging Channel = 11
)

// Level represents the ETW logging level. There are several predefined levels
// that are commonly used, but technically anything from 0-255 is allowed.
// Lower levels indicate more important events, and 0 indicates an event that
// will always be collected.
type Level uint8

// Predefined ETW log levels.
const (
	LevelAlways Level = iota
	LevelCritical
	LevelError
	LevelWarning
	LevelInfo
	LevelVerbose
)

// Event represents a single ETW event. It can have field metadata and data
// added to it, and then be logged via a provider to actually send it to ETW.
type Event struct {
	Descriptor *EventDescriptor
	Metadata   *EventMetadata
	Data       *EventData
}

// NewEvent returns a new instance of an event object.
func NewEvent(name string, descriptor *EventDescriptor) *Event {
	return &Event{
		Descriptor: descriptor,
		Metadata:   NewEventMetadata(name),
		Data:       &EventData{},
	}
}

// EventDescriptor represents various metadata for an ETW event.
type EventDescriptor struct {
	id      uint16
	version uint8
	Channel Channel
	Level   Level
	Opcode  uint8
	Task    uint16
	Keyword uint64
}

// NewEventDescriptor returns an EventDescriptor initialized for use with
// TraceLogging.
func NewEventDescriptor() *EventDescriptor {
	// Standard TraceLogging events default to the TraceLogging channel, and
	// verbose level.
	return &EventDescriptor{
		id:      0,
		version: 0,
		Channel: ChannelTraceLogging,
		Level:   LevelVerbose,
		Opcode:  0,
		Task:    0,
		Keyword: 0,
	}
}

// Identity returns the identity of the event. If the identity is not 0, it
// should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant.
func (ed *EventDescriptor) Identity() uint32 {
	return (uint32(ed.version) << 16) | uint32(ed.id)
}

// SetIdentity sets the identity of the event. If the identity is not 0, it
// should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant.
func (ed *EventDescriptor) SetIdentity(identity uint32) {
	ed.id = uint16(identity)
	ed.version = uint8(identity >> 16)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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 util

import (
	"os/exec"
	"strings"

	"github.com/golang/glog"
)

func GetHostname(hostnameOverride string) string {
	hostname := []byte(hostnameOverride)
	if string(hostname) == "" {
		// Note: We use exec here instead of os.Hostname() because we
		// want the FQDN, and this is the easiest way to get it.
		fqdn, err := exec.Command("uname", "-n").Output()
		if err != nil {
			glog.Fatalf("Couldn't determine hostname: %v", err)
		}
		hostname = fqdn
	}
	return strings.ToLower(strings.TrimSpace(string(hostname)))
}
<commit_msg>Remove deprecated comment.<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

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 util

import (
	"os/exec"
	"strings"

	"github.com/golang/glog"
)

func GetHostname(hostnameOverride string) string {
	hostname := []byte(hostnameOverride)
	if string(hostname) == "" {
		fqdn, err := exec.Command("uname", "-n").Output()
		if err != nil {
			glog.Fatalf("Couldn't determine hostname: %v", err)
		}
		hostname = fqdn
	}
	return strings.ToLower(strings.TrimSpace(string(hostname)))
}
<|endoftext|>