<commit_before>// +build !js

package webrtc

import (
	"sync/atomic"

	"github.com/pion/interceptor"
	"github.com/pion/interceptor/pkg/nack"
	"github.com/pion/interceptor/pkg/report"
	"github.com/pion/interceptor/pkg/twcc"
	"github.com/pion/rtp"
	"github.com/pion/sdp/v3"
)

// RegisterDefaultInterceptors will register some useful interceptors.
// If you want to customize which interceptors are loaded, you should copy the
// code from this method and remove unwanted interceptors.
func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil {
		return err
	}

	if err := ConfigureRTCPReports(interceptorRegistry); err != nil {
		return err
	}

	if err := ConfigureTWCCSender(mediaEngine, interceptorRegistry); err != nil {
		return err
	}

	return nil
}

// ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports
func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error {
	reciver, err := report.NewReceiverInterceptor()
	if err != nil {
		return err
	}

	sender, err := report.NewSenderInterceptor()
	if err != nil {
		return err
	}

	interceptorRegistry.Add(reciver)
	interceptorRegistry.Add(sender)
	return nil
}

// ConfigureNack will setup everything necessary for handling generating/responding to nack messages.
func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	generator, err := nack.NewGeneratorInterceptor()
	if err != nil {
		return err
	}

	responder, err := nack.NewResponderInterceptor()
	if err != nil {
		return err
	}

	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo)
	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo)
	interceptorRegistry.Add(responder)
	interceptorRegistry.Add(generator)
	return nil
}

// ConfigureTWCCHeaderExtensionSender will setup everything necessary for adding
// a TWCC header extension to outgoing RTP packets. This will allow the remote peer to generate TWCC reports.
func ConfigureTWCCHeaderExtensionSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo)
	if err != nil {
		return err
	}
	i, err := twcc.NewHeaderExtensionInterceptor()
	if err != nil {
		return err
	}
	interceptorRegistry.Add(i)
	return err
}

// ConfigureTWCCSender will setup everything necessary for generating TWCC reports.
func ConfigureTWCCSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeVideo)
	err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo)
	if err != nil {
		return err
	}
	generator, err := twcc.NewSenderInterceptor()
	if err != nil {
		return err
	}
	interceptorRegistry.Add(generator)
	return nil
}

type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }

func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
	if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil {
		return writer.Write(header, payload, interceptor.Attributes{})
	}

	return 0, nil
}

func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) {
	packet := &rtp.Packet{}
	if err := packet.Unmarshal(b); err != nil {
		return 0, err
	}

	return i.WriteRTP(&packet.Header, packet.Payload)
}

func createStreamInfo(id string, ssrc SSRC, payloadType PayloadType, codec RTPCodecCapability, webrtcHeaderExtensions []RTPHeaderExtensionParameter) *interceptor.StreamInfo {
	headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions))
	for _, h := range webrtcHeaderExtensions {
		headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI})
	}

	feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback))
	for _, f := range codec.RTCPFeedback {
		feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter})
	}

	return &interceptor.StreamInfo{
		ID:                  id,
		Attributes:          interceptor.Attributes{},
		SSRC:                uint32(ssrc),
		PayloadType:         uint8(payloadType),
		RTPHeaderExtensions: headerExtensions,
		MimeType:            codec.MimeType,
		ClockRate:           codec.ClockRate,
		Channels:            codec.Channels,
		SDPFmtpLine:         codec.SDPFmtpLine,
		RTCPFeedback:        feedbacks,
	}
}
<commit_msg>Enabel TWCC for audio by default<commit_after>// +build !js

package webrtc

import (
	"sync/atomic"

	"github.com/pion/interceptor"
	"github.com/pion/interceptor/pkg/nack"
	"github.com/pion/interceptor/pkg/report"
	"github.com/pion/interceptor/pkg/twcc"
	"github.com/pion/rtp"
	"github.com/pion/sdp/v3"
)

// RegisterDefaultInterceptors will register some useful interceptors.
// If you want to customize which interceptors are loaded, you should copy the
// code from this method and remove unwanted interceptors.
func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil {
		return err
	}

	if err := ConfigureRTCPReports(interceptorRegistry); err != nil {
		return err
	}

	if err := ConfigureTWCCSender(mediaEngine, interceptorRegistry); err != nil {
		return err
	}

	return nil
}

// ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports
func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error {
	reciver, err := report.NewReceiverInterceptor()
	if err != nil {
		return err
	}

	sender, err := report.NewSenderInterceptor()
	if err != nil {
		return err
	}

	interceptorRegistry.Add(reciver)
	interceptorRegistry.Add(sender)
	return nil
}

// ConfigureNack will setup everything necessary for handling generating/responding to nack messages.
func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	generator, err := nack.NewGeneratorInterceptor()
	if err != nil {
		return err
	}

	responder, err := nack.NewResponderInterceptor()
	if err != nil {
		return err
	}

	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo)
	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo)
	interceptorRegistry.Add(responder)
	interceptorRegistry.Add(generator)
	return nil
}

// ConfigureTWCCHeaderExtensionSender will setup everything necessary for adding
// a TWCC header extension to outgoing RTP packets. This will allow the remote peer to generate TWCC reports.
func ConfigureTWCCHeaderExtensionSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil {
		return err
	}

	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil {
		return err
	}

	i, err := twcc.NewHeaderExtensionInterceptor()
	if err != nil {
		return err
	}

	interceptorRegistry.Add(i)
	return nil
}

// ConfigureTWCCSender will setup everything necessary for generating TWCC reports.
func ConfigureTWCCSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeVideo)
	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil {
		return err
	}

	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeAudio)
	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil {
		return err
	}

	generator, err := twcc.NewSenderInterceptor()
	if err != nil {
		return err
	}

	interceptorRegistry.Add(generator)
	return nil
}

type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }

func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
	if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil {
		return writer.Write(header, payload, interceptor.Attributes{})
	}

	return 0, nil
}

func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) {
	packet := &rtp.Packet{}
	if err := packet.Unmarshal(b); err != nil {
		return 0, err
	}

	return i.WriteRTP(&packet.Header, packet.Payload)
}

func createStreamInfo(id string, ssrc SSRC, payloadType PayloadType, codec RTPCodecCapability, webrtcHeaderExtensions []RTPHeaderExtensionParameter) *interceptor.StreamInfo {
	headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions))
	for _, h := range webrtcHeaderExtensions {
		headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI})
	}

	feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback))
	for _, f := range codec.RTCPFeedback {
		feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter})
	}

	return &interceptor.StreamInfo{
		ID:                  id,
		Attributes:          interceptor.Attributes{},
		SSRC:                uint32(ssrc),
		PayloadType:         uint8(payloadType),
		RTPHeaderExtensions: headerExtensions,
		MimeType:            codec.MimeType,
		ClockRate:           codec.ClockRate,
		Channels:            codec.Channels,
		SDPFmtpLine:         codec.SDPFmtpLine,
		RTCPFeedback:        feedbacks,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/TeaMeow/KitSvc/service/store"
	"github.com/go-kit/kit/endpoint"
	kitlog "github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	consulsd "github.com/go-kit/kit/sd/consul"
	httptransport "github.com/go-kit/kit/transport/http"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	consulapi "github.com/hashicorp/consul/api"
	"github.com/jetbasrawi/go.geteventstore"
	"github.com/jinzhu/gorm"
	stdprometheus "github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/context"
)

// The functions, structs down below are the core methods,
// you shouldn't edit them until you know what you're doing,
// or you understand how KitSvc works.
//
// Or if you are brave enough ;)

func main() {

	// Command line flags.
	var (
		listenPort = flag.String("listen", ":"+os.Getenv("KITSVC_PORT"), "HTTP listen address")
		resetDB    = flag.Bool("reinitialize-database", false, "Set true to reinitialize the database, it's useful with the unit testing.")
	)
	flag.Parse()

	r, _ := strconv.ParseBool(fmt.Sprint(reflect.ValueOf(resetDB).Elem()))

	// Create the logger with the specified listen port.
	logger := createLogger(listenPort)
	// Create the database connection.
	db := createDatabase()
	//
	s := createStore(r, db)
	//
	es := createEventStore()

	// Create the main service with what it needs.
	_, _, mux := createService(logger, es, s)
	// Register the service to the service registry.
	registerService(logger)

	// Log the ports.
	logger.Log("msg", "HTTP", "addr", *listenPort)
	//
	http.Handle("/", mux)
	// Start the service and listening to the requests.
	logger.Log("err", http.ListenAndServe(*listenPort, nil))
}

//
//
//
//
//

// InstrumentingMiddleware represents a middleware of the instrumenting.
type InstrumentingMiddleware struct {
	requestCount   metrics.Counter
	requestLatency metrics.Histogram
	countResult    metrics.Histogram
	Service
}

// createInstruMiddleware creates the instrumenting middleware.
func createInstruMiddleware() ServiceMiddleware {

	fieldKeys := []string{"method", "error"}

	// Number of requests received.
	requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "request_count",
		Help:      "Number of requests received.",
	}, fieldKeys)

	// Total duration of requests in microseconds.
	requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "request_latency_microseconds",
		Help:      "Total duration of requests in microseconds.",
	}, fieldKeys)

	// The result of each count method.
	countResult := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "count_result",
		Help:      "The result of each count method.",
	}, []string{})

	return func(next Service) Service {
		return InstrumentingMiddleware{requestCount, requestLatency, countResult, next}
	}
}

//
//
//
//
//

type eventListener struct {
	event   string
	body    map[string]interface{}
	meta    map[string]string
	handler func(map[string]interface{}, map[string]string)
}

func createEventStore() *goes.Client {
	client, err := goes.NewClient(nil, os.Getenv("KITSVC_ES_SERVER_URL"))
	if err != nil {
		panic(err)
	}

	client.SetBasicAuth(os.Getenv("KITSVC_ES_USERNAME"), os.Getenv("KITSVC_ES_PASSWORD"))

	return client
}

func setEventSubscription(client *goes.Client, listeners []eventListener) {

	for _, v := range listeners {

		//

		reader := client.NewStreamReader(v.event)

		for reader.Next() {
			if reader.Err() != nil {
				if _, ok := reader.Err().(*goes.ErrNoMoreEvents); ok {
					continue
				} else if _, ok := reader.Err().(*goes.ErrNotFound); ok {
					writer := client.NewStreamWriter(v.event)
					err := writer.Append(nil, goes.NewEvent("", "", map[string]string{}, map[string]string{}))
					if err != nil {
						panic(err)
					}
					continue
				} else if match, _ := regexp.MatchString(".*connection refused.*", reader.Err().Error()); match {
					time.Sleep(time.Second * 2)
					continue
				} else {
					panic(reader.Err())
				}
			}

			err := reader.Scan(&v.body, &v.meta)
			if err != nil {
				panic(err)
			}

			v.handler(v.body, v.meta)
		}
	}
}

//
//
//
//
//

func createStore(resetDB bool, db *gorm.DB) store.Store {
	s := store.Store{DB: db}

	if resetDB {
		s.Downstream()
		s.Upstream()
	}

	return s
}

//
//
//
//
//

type service struct {
	Store store.Store
	ES    *goes.Client
}

// ServiceMiddleware is a chainable behavior modifier for Service.
type ServiceMiddleware func(Service) Service

type Err struct {
	Message error
	Payload interface{}
}

func (e Err) Error() string {
	return e.Message.Error()
}

type ErrInfo struct {
	Text   error
	Status int
	Code   string
}

func (e ErrInfo) Error() string {
	return e.Text.Error()
}

type response struct {
	Status  string      `json:"status"`
	Code    string      `json:"code"`
	Message string      `json:"message"`
	Payload interface{} `json:"payload"`
}

func errorEncoder(c context.Context, err error, w http.ResponseWriter) {
	var status int
	var code string
	var msg string
	var payload interface{}

	switch err.(type) {
	case Err:
		status, msg, code, payload =
			err.(Err).Message.(ErrInfo).Status,
			err.(Err).Message.(ErrInfo).Text.Error(),
			err.(Err).Message.(ErrInfo).Code,
			err.(Err).Payload

	default:
		status, msg, code, payload =
			http.StatusBadRequest,
			"Cannot parse the JSON content.",
			"error",
			nil
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(response{
		Status:  "error",
		Code:    code,
		Message: msg,
		Payload: payload,
	})
}

func encodeResponse(_ context.Context, w http.ResponseWriter, resp interface{}) error {
	w.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(response{
		Status:  "success",
		Code:    "success",
		Message: "",
		Payload: resp,
	})
}

// createService creates the main service by setting the handlers and preparing the middlewares.
func createService(logger kitlog.Logger, es *goes.Client, s store.Store) (Service, context.Context, *mux.Router) {

	var svc Service
	svc = service{Store: s, ES: es}
	svc = createLoggingMiddleware(logger)(svc)
	svc = createInstruMiddleware()(svc)

	ctx := context.Background()
	options := []httptransport.ServerOption{
		httptransport.ServerErrorEncoder(errorEncoder),
	}

	mux := setServiceSubscription(ctx, options, svc, serviceHandlers(ctx, options, svc))
	go setEventSubscription(es, eventListeners(svc))

	return svc, ctx, mux
}

type serviceHandler struct {
	method  string
	pattern string
	handler http.Handler
}

func setServiceSubscription(ctx context.Context, opts []httptransport.ServerOption, svc Service, handlers []serviceHandler) *mux.Router {

	r := mux.NewRouter()

	consulsdHandler := httptransport.NewServer(ctx, makeServiceDiscoveryEndpoint(svc), decodeServiceDiscoveryRequest, encodeResponse, opts...)

	r.Handle("/sd_health", consulsdHandler).Methods("GET")
	r.Handle("/metrics", stdprometheus.Handler()).Methods("GET")

	for _, v := range handlers {
		r.Handle(v.pattern, v.handler).Methods(v.method)
	}

	return r
}

//
//
//
//
//

// LoggingMiddleware represents a middleware of the logger.
type LoggingMiddleware struct {
	Logger kitlog.Logger
	Service
}

// createLoggingMiddleware creates the logging middleware.
func createLoggingMiddleware(logger kitlog.Logger) ServiceMiddleware {
	return func(next Service) Service {
		return LoggingMiddleware{Logger: logger, Service: next}
	}
}

// createLogger creates the logger with the specified port which tracks the function callers.
func createLogger(port *string) kitlog.Logger {
	var logger kitlog.Logger
	logger = kitlog.NewLogfmtLogger(os.Stderr)
	logger = kitlog.NewContext(logger).With("listen", port).With("caller", kitlog.DefaultCaller)

	return logger
}

//
//
//
//
//

// registerService register the service to the service discovery server(consul).
func registerService(logger kitlog.Logger) {
	p, _ := strconv.Atoi(os.Getenv("KITSVC_PORT"))

	info := consulapi.AgentServiceRegistration{
		Name: os.Getenv("KITSVC_NAME"),
		Port: p,
		Tags: strings.Split(os.Getenv("KITSVC_CONSUL_TAGS"), ","),
		Check: &consulapi.AgentServiceCheck{
			HTTP:     os.Getenv("KITSVC_URL") + "/sd_health",
			Interval: os.Getenv("KITSVC_CONSUL_CHECK_INTERVAL"),
			Timeout:  os.Getenv("KITSVC_CONSUL_CHECK_TIMEOUT"),
		},
	}

	apiConfig := consulapi.DefaultConfig()
	apiClient, _ := consulapi.NewClient(apiConfig)
	client := consulsd.NewClient(apiClient)
	reg := consulsd.NewRegistrar(client, &info, logger)

	// Deregister the service when exiting the program.
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		for range ch {
			reg.Deregister()
			os.Exit(1)
		}
	}()

	// Register the service.
	reg.Register()
}

type sdResponse struct {
	P string `json:"pong"`
}

func makeServiceDiscoveryEndpoint(svc Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		return sdResponse{"pong"}, nil
	}
}

func decodeServiceDiscoveryRequest(_ context.Context, r *http.Request) (interface{}, error) {
	return nil, nil
}

//
//
//
//
//

// createDatabase creates the database connection.
func createDatabase() *gorm.DB {

	db, err := gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%s&loc=%s",
		os.Getenv("KITSVC_DATABASE_USER"),
		os.Getenv("KITSVC_DATABASE_PASSWORD"),
		os.Getenv("KITSVC_DATABASE_HOST"),
		os.Getenv("KITSVC_DATABASE_NAME"),
		os.Getenv("KITSVC_DATABASE_CHARSET"),
		os.Getenv("KITSVC_DATABASE_PARSE_TIME"),
		os.Getenv("KITSVC_DATABASE_LOC"),
	))
	if err != nil {
		panic(err)
	}

	return db
}
<commit_msg>Added H type, comments, register after recv events<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/TeaMeow/KitSvc/service/store"
	"github.com/go-kit/kit/endpoint"
	kitlog "github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	consulsd "github.com/go-kit/kit/sd/consul"
	httptransport "github.com/go-kit/kit/transport/http"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	consulapi "github.com/hashicorp/consul/api"
	"github.com/jetbasrawi/go.geteventstore"
	"github.com/jinzhu/gorm"
	stdprometheus "github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/context"
)

type H map[string]interface{}

// MapString converts type H to map[string]string
func (h H) MapString() map[string]string {
	m := make(map[string]string)

	for k, v := range h {
		m[k] = fmt.Sprint(v)
	}

	return m
}

func main() {

	// Command line flags.
	var (
		listenPort = flag.String("listen", ":"+os.Getenv("KITSVC_PORT"), "HTTP listen address")
		resetDB    = flag.Bool("reinitialize-database", false, "Set true to reinitialize the database, it's useful with the unit testing.")
	)
	flag.Parse()

	// Get the boolean from the pointer by using the reflect package.
	r, _ := strconv.ParseBool(fmt.Sprint(reflect.ValueOf(resetDB).Elem()))

	// Create the logger with the specified listen port.
	logger := createLogger(listenPort)
	// Create the database connection.
	db := createDatabase()
	// Create the store with the database connection.
	s := createStore(r, db)
	// Create the event store.
	es := createEventStore()
	// Create the main service with what it needs.
	_, _, mux := createService(logger, es, s)

	// Log the ports.
	logger.Log("msg", "HTTP", "addr", *listenPort)
	// Start the service and listening to the requests and let the mux router handles every things.
	logger.Log("err", http.ListenAndServe(*listenPort, mux))
}

// InstrumentingMiddleware describes
// a service (as opposed to endpoint) middleware.
//
// The instrumenting middleware instruments
// the performance, time wasted of the operations.
type InstrumentingMiddleware struct {
	requestCount   metrics.Counter
	requestLatency metrics.Histogram
	countResult    metrics.Histogram
	Service
}

// createInstruMiddleware creates the instrumenting middleware.
func createInstruMiddleware() ServiceMiddleware {

	fieldKeys := []string{"method", "error"}

	// Number of requests received.
	requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "request_count",
		Help:      "Number of requests received.",
	}, fieldKeys)

	// Total duration of requests in microseconds.
	requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "request_latency_microseconds",
		Help:      "Total duration of requests in microseconds.",
	}, fieldKeys)

	// The result of each count method.
	countResult := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
		Namespace: os.Getenv("KITSVC_PROMETHEUS_NAMESPACE"),
		Subsystem: os.Getenv("KITSVC_PROMETHEUS_SUBSYSTEM"),
		Name:      "count_result",
		Help:      "The result of each count method.",
	}, []string{})

	return func(next Service) Service {
		return InstrumentingMiddleware{requestCount, requestLatency, countResult, next}
	}
}

// eventListener represents an event listener.
//
// We'll register the event listeners and
// listen for the incoming event
// from the event store.
type eventListener struct {
	event   string
	body    map[string]interface{}
	meta    map[string]interface{}
	handler func(map[string]interface{}, map[string]interface{})
}

// createEventStore creates a client of the event store.
func createEventStore() *goes.Client {
	client, err := goes.NewClient(nil, os.Getenv("KITSVC_ES_SERVER_URL"))
	if err != nil {
		panic(err)
	}

	client.SetBasicAuth(os.Getenv("KITSVC_ES_USERNAME"), os.Getenv("KITSVC_ES_PASSWORD"))

	return client
}

// setEventSubscription applies the event handlers.
func setEventSubscription(client *goes.Client, logger kitlog.Logger, listeners []eventListener) {

	// The toggle used to detect if the events were all replayed or not.
	played := make(chan kitlog.Logger)
	sent := false

	// Register the service to sd if the events were all replayed.
	go func() {
		// If the events were all replayed.
		if l := <-played; l != nil {
			// then register the service to the service registry.
			registerService(l)
			// End the goroutine
			return
		}
	}()

	// Each of the listener.
	for _, v := range listeners {
		// Create the the stream reader for listening the specified event(stream).
		reader := client.NewStreamReader(v.event)

		// Read the next event.
		for reader.Next() {

			if reader.Err() != nil {
				switch reader.Err().(type) {

				// Continue if there's no more event.
				case *goes.ErrNoMoreEvents:

					// Since there're no more messages can read. We've replayed all the events,
					// and it's time to register the service to the sd because we're ready.
					if !sent {
						// Send the logger to the played channel because we need the logger.
						played <- logger
						// Set the sent toggle as true so we won't send the logger to the channel again.
						sent = true
						// Close the unused channel.
						close(played)
					}

					// When there are no more event in the stream, set LongPoll.
					// The server will wait for 15 seconds in this case or until
					// events become available on the stream.
					reader.LongPoll(5)

				// Create an empty event if the stream hasn't been created.
				case *goes.ErrNotFound:
					writer := client.NewStreamWriter(v.event)

					// Create am empty stream.
					err := writer.Append(nil, goes.NewEvent("", "", map[string]string{}, map[string]string{}))
					if err != nil {
						panic(err)
					}
					continue

				// Sleep for 5 seconds and try again if the EventStore was not connected.
				case *url.Error, *goes.ErrTemporarilyUnavailable:
					fmt.Println("Cannot conenct to the Event Sotre, try again after 5 seconds.")
					<-time.After(time.Duration(5) * time.Second)

				// Bye bye if really error.
				default:
					panic(reader.Err())
				}

			} else {
				// Mapping the event data.
				err := reader.Scan(&v.body, &v.meta)
				if err != nil {
					panic(err)
				}

				// Skip if the body or the meta is empty (might be the empty one which we created for the new stream).
				if len(v.body) == 0 {
					continue
				}

				// Call to the event handler.
				v.handler(v.body, v.meta)
			}
		}
	}
}

// createStore creates the store with the database connection,
// also creates/destorys the database tables.
//
// The store is used to interactive with the database,
// we'll modify the database from the store,
// not from the controller.
func createStore(resetDB bool, db *gorm.DB) store.Store {
	s := store.Store{DB: db}

	if resetDB {
		s.Downstream()
		s.Upstream()
	}

	return s
}

// service represents the service concrete.
//
// The service concrete contains
// the operations of the service can do,
// and it also contains the modules that we can use in the operations.
type service struct {
	Store store.Store
	ES    *goes.Client
}

// ServiceMiddleware is a chainable behavior modifier for Service.
type ServiceMiddleware func(Service) Service

// Err represents the error response.
type Err struct {
	Message error
	Payload interface{}
}

// Error returns the error string from the Err struct.
func (e Err) Error() string {
	return e.Message.Error()
}

// ErrInfo represents the information of the operation error.
type ErrInfo struct {
	Text   error
	Status int
	Code   string
}

// Error returns the error string from the ErrInfo struct.
func (e ErrInfo) Error() string {
	return e.Text.Error()
}

// response represents the response of the endpoints.
type response struct {
	Status  string      `json:"status"`
	Code    string      `json:"code"`
	Message string      `json:"message"`
	Payload interface{} `json:"payload"`
}

// errorEncoder encodes the error information to an endpoint response.
func errorEncoder(c context.Context, err error, w http.ResponseWriter) {
	var status int
	var code string
	var msg string
	var payload interface{}

	switch err.(type) {

	// The error which creates by the operations of the service.
	case Err:
		status, msg, code, payload =
			err.(Err).Message.(ErrInfo).Status,
			err.(Err).Message.(ErrInfo).Text.Error(),
			err.(Err).Message.(ErrInfo).Code,
			err.(Err).Payload

	// The unknown error, JSON parse error most of the time.
	default:
		status, msg, code, payload =
			http.StatusBadRequest,
			"Cannot parse the JSON content.",
			"error",
			nil
	}

	// Set the JSON content type.
	w.Header().Set("Content-Type", "application/json")
	// Set the status code.
	w.WriteHeader(status)

	json.NewEncoder(w).Encode(response{
		Status:  "error",
		Code:    code,
		Message: msg,
		Payload: payload,
	})
}

// encodeResponse encodes the data to a response.
func encodeResponse(_ context.Context, w http.ResponseWriter, resp interface{}) error {
	w.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(response{
		Status:  "success",
		Code:    "success",
		Message: "",
		Payload: resp,
	})
}

// createService creates the main service by setting the handlers and preparing the middlewares.
func createService(logger kitlog.Logger, es *goes.Client, s store.Store) (Service, context.Context, *mux.Router) {

	// Create the service and the middlewares.
	var svc Service
	svc = service{Store: s, ES: es}
	svc = createLoggingMiddleware(logger)(svc)
	svc = createInstruMiddleware()(svc)

	// The context and the server options.
	ctx := context.Background()
	options := []httptransport.ServerOption{
		httptransport.ServerErrorEncoder(errorEncoder),
	}

	// Set the operation handlers and get the mux router.
	mux := setServiceSubscription(ctx, options, svc, serviceHandlers(ctx, options, svc))
	// Set the event handlers with goroutine so it won't blocked.
	go setEventSubscription(es, logger, eventListeners(svc))

	return svc, ctx, mux
}

// serviceHandler represents a service handler.
type serviceHandler struct {
	method  string
	pattern string
	handler http.Handler
}

// setServiceSubscription sets the service handlers.
func setServiceSubscription(ctx context.Context, opts []httptransport.ServerOption, svc Service, handlers []serviceHandler) *mux.Router {

	// Create a mux router to handle the incoming requests.
	r := mux.NewRouter()

	// The service discovery health check handler.
	consulsdHandler := httptransport.NewServer(ctx, makeServiceDiscoveryEndpoint(svc), decodeServiceDiscoveryRequest, encodeResponse, opts...)
	r.Handle("/sd_health", consulsdHandler).Methods("GET")

	// The metrics handler for prometheus.
	r.Handle("/metrics", stdprometheus.Handler()).Methods("GET")

	// Apply the other custom handlers.
	for _, v := range handlers {
		r.Handle(v.pattern, v.handler).Methods(v.method)
	}

	return r
}

// LoggingMiddleware describes
// a service (as opposed to endpoint) middleware.
//
// The logging middleware logs the data of the incoming request
// and the output data.
type LoggingMiddleware struct {
	Logger kitlog.Logger
	Service
}

// createLoggingMiddleware creates the logging middleware.
func createLoggingMiddleware(logger kitlog.Logger) ServiceMiddleware {
	return func(next Service) Service {
		return LoggingMiddleware{Logger: logger, Service: next}
	}
}

// createLogger creates the logger with the specified port which tracks the function callers.
func createLogger(port *string) kitlog.Logger {
	var logger kitlog.Logger
	logger = kitlog.NewLogfmtLogger(os.Stderr)
	logger = kitlog.NewContext(logger).With("listen", port).With("caller", kitlog.DefaultCaller)

	return logger
}

// registerService registers the service
// to the service discovery server(consul).
//
// So the gateway can call to the service
// without the extra settings or restarting.
func registerService(logger kitlog.Logger) {
	p, _ := strconv.Atoi(os.Getenv("KITSVC_PORT"))

	info := consulapi.AgentServiceRegistration{
		Name: os.Getenv("KITSVC_NAME"),
		Port: p,
		Tags: strings.Split(os.Getenv("KITSVC_CONSUL_TAGS"), ","),
		Check: &consulapi.AgentServiceCheck{
			HTTP:     os.Getenv("KITSVC_URL") + "/sd_health",
			Interval: os.Getenv("KITSVC_CONSUL_CHECK_INTERVAL"),
			Timeout:  os.Getenv("KITSVC_CONSUL_CHECK_TIMEOUT"),
		},
	}

	apiConfig := consulapi.DefaultConfig()
	apiClient, _ := consulapi.NewClient(apiConfig)
	client := consulsd.NewClient(apiClient)
	reg := consulsd.NewRegistrar(client, &info, logger)

	// Deregister the service when exiting the program.
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		for range ch {
			reg.Deregister()
			os.Exit(1)
		}
	}()

	// Register the service.
	reg.Register()
}

// sdResponse represents the response of the health check for consul.
type sdResponse struct {
	P string `json:"pong"`
}

func makeServiceDiscoveryEndpoint(svc Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		return sdResponse{"pong"}, nil
	}
}

func decodeServiceDiscoveryRequest(_ context.Context, r *http.Request) (interface{}, error) {
	return nil, nil
}

// createDatabase creates the database connection by using gorm.
// https://github.com/jinzhu/gorm
//
//
//
func createDatabase() *gorm.DB {

	db, err := gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%s&loc=%s",
		os.Getenv("KITSVC_DATABASE_USER"),
		os.Getenv("KITSVC_DATABASE_PASSWORD"),
		os.Getenv("KITSVC_DATABASE_HOST"),
		os.Getenv("KITSVC_DATABASE_NAME"),
		os.Getenv("KITSVC_DATABASE_CHARSET"),
		os.Getenv("KITSVC_DATABASE_PARSE_TIME"),
		os.Getenv("KITSVC_DATABASE_LOC"),
	))
	if err != nil {
		panic(err)
	}

	return db
}
<|endoftext|>


<commit_before>// SILVER - Service Wrapper
//
// Copyright (c) 2014 PaperCut Software http://www.papercut.com/
// Use of this source code is governed by an MIT or GPL Version 2 license.
// See the project's LICENSE file for more information.
//
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sync"
	"time"

	"github.com/kardianos/service"

	"github.com/robfig/cron"

	"github.com/papercutsoftware/silver/lib/logging"
	"github.com/papercutsoftware/silver/lib/pathutils"
	"github.com/papercutsoftware/silver/service/cmdutil"
	"github.com/papercutsoftware/silver/service/config"
	"github.com/papercutsoftware/silver/service/svcutil"
)

const (
	defaultRefreshPoll = 10 * time.Second
)

type context struct {
	conf         *config.Config
	terminate    chan struct{}
	logger       *log.Logger
	runningGroup sync.WaitGroup
	cronManager  *cron.Cron
}

func main() {

	ctx := &context{
		terminate: make(chan struct{}),
	}

	// Parse config (we don't action any errors quite yet)
	var err error
	ctx.conf, err = loadConf()
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: Invalid config - %v\n", err)
		os.Exit(1)
	}

	action, actionArgs, err := parse(os.Args)
	if err != nil {
		printUsage(ctx.conf.ServiceDescription.DisplayName, ctx.conf.ServiceDescription.Description)
		os.Exit(1)
	}

	if err := os.Chdir(exeFolder()); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: Unable to set working directory - %v\n", err)
		os.Exit(1)
	}

	switch action {
	case "command":
		var cmdName string
		var cmdExtraArgs []string
		if len(actionArgs) >= 3 {
			cmdName = actionArgs[2]
		}
		if len(actionArgs) >= 4 {
			cmdExtraArgs = actionArgs[3:]
		}
		execCommand(ctx, cmdName, cmdExtraArgs)
	case "validate":
		fmt.Println("Config is valid")
		os.Exit(0)
	default:
		osServiceControl(ctx)
	}
}

func osServiceControl(ctx *context) {
	// Setup log file out
	logFile := ctx.conf.ServiceConfig.LogFile
	maxSize := int64(ctx.conf.ServiceConfig.LogFileMaxSizeMb) * 1024 * 1024
	if logFile == "" {
		logFile = serviceName() + ".log"
	}
	ctx.logger = logging.NewFileLoggerWithMaxSize(logFile, maxSize)

	// Setup service
	svcConfig := &service.Config{
		Name:        serviceName(),
		DisplayName: ctx.conf.ServiceDescription.DisplayName,
		Description: ctx.conf.ServiceDescription.Description,
	}

	osService := &osService{ctx: ctx}
	svc, err := service.New(osService, svcConfig)
	if err != nil {
		fmt.Printf("ERROR: Invalid service config: %v\n", err)
		os.Exit(1)
	}

	if len(os.Args) > 1 && os.Args[1] != "run" {
		err = service.Control(svc, os.Args[1])
		if err != nil {
			fmt.Printf("ERROR: Invalid service command: %v\n", err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	err = svc.Run()
	if err != nil {
		fmt.Printf("ERROR: %v\n", err)
		os.Exit(1)
	}

	pidFile := ctx.conf.ServiceConfig.PidFile
	if pidFile != "" {
		ioutil.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0644)
	}
}

func printUsage(svcDisplayName, svcDesc string) {
	fmt.Printf("%s (%s)\n", svcDisplayName,
		serviceName())
	fmt.Printf("%s\n\n", svcDesc)
	fmt.Printf("Usage:\n")
	fmt.Printf("%s [install|uninstall|start|stop|command|validate|run|help] [command-name]\n", exeName())
	fmt.Printf("  install   - Install the service.\n")
	fmt.Printf("  uninstall - Remove/uninstall the service.\n")
	fmt.Printf("  start     - Start an installed service.\n")
	fmt.Printf("  stop      - Stop an installed service.\n")
	fmt.Printf("  validate  - Test the configuration file.\n")
	fmt.Printf("  run       - Run service on in command-line mode.\n")
	fmt.Printf("  command   - Run a command [command-name].\n")
	fmt.Printf("  help      - This usage message.\n")
}

func loadConf() (conf *config.Config, err error) {
	// FIXME: Not Get this function out of utils.
	confPath := getConfigFilePath()
	vars := config.ReplacementVars{
		ServiceName: serviceName(),
		ServiceRoot: exeFolder(),
	}
	conf, err = config.LoadConfig(confPath, vars)
	if err != nil {
		return nil, err
	}

	// Merge in any include files
	for _, include := range conf.Include {
		conf, err = config.MergeInclude(*conf, include, vars)
		if err != nil {
			return nil, err
		}
	}
	return conf, err
}

func execCommand(ctx *context, cmdName string, cmdExtraArgs []string) {
	if len(ctx.conf.Commands) == 0 {
		fmt.Fprintf(os.Stderr, "There are no commands configured!\n")
		os.Exit(1)
	}
	var cmd *config.Command
	for _, c := range ctx.conf.Commands {
		if c.Name == cmdName {
			cmd = &c
			break
		}
	}

	if cmd == nil {
		fmt.Fprintf(os.Stderr, "Valid commands are:\n")
		for _, command := range ctx.conf.Commands {
			fmt.Fprintf(os.Stderr, "    %s\n", command.Name)
		}
		os.Exit(1)
	}

	cmdConf := cmdutil.CommandConfig{}
	cmdConf.Path = pathutils.FindLastFile(cmd.Path)
	cmdConf.Args = cmd.Args
	cmdConf.ExecTimeout = (time.Second * time.Duration(cmd.TimeoutSecs))

	exitCode, err := cmdutil.Execute(cmdConf)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
	}
	os.Exit(exitCode)
}

type osService struct {
	ctx *context
}

func (o *osService) Start(s service.Service) error {
	msg := fmt.Sprintf("Service '%s' started.", serviceName())
	o.ctx.logger.Printf(msg)
	sysLogger, err := s.Logger(nil)
	if err != nil {
		sysLogger.Info(msg)
	}

	go watchForReload(o.ctx)
	return nil
}

func doStart(ctx *context) {
	execStartupTasks(ctx)
	setupScheduledTasks(ctx)
	startServices(ctx)
}

func (o *osService) Stop(s service.Service) error {
	o.ctx.logger.Printf(fmt.Sprintf("Stopping '%s' service...", serviceName()))

	doStop(o.ctx)

	pidFile := o.ctx.conf.ServiceConfig.PidFile
	if pidFile != "" {
		os.Remove(pidFile)
	}

	msg := fmt.Sprintf("Stopped '%s' service.", serviceName())
	o.ctx.logger.Printf(msg)

	sysLogger, err := s.Logger(nil)
	if err != nil {
		sysLogger.Info(msg)
	}
	return nil
}

func doStop(ctx *context) {
	// Create stop file... another method to signal services to stop.
	stopFile := ctx.conf.ServiceConfig.StopFile
	if stopFile == "" {
		stopFile = ".stop"
	}
	if stopFile == "disabled" {
		return
	}
	ioutil.WriteFile(stopFile, nil, 0644)
	defer os.Remove(stopFile)
	if ctx.cronManager != nil {
		ctx.cronManager.Stop()
	}
	if ctx.terminate != nil {
		close(ctx.terminate)
	}
	ctx.runningGroup.Wait()
}

func watchForReload(ctx *context) {
	f := ctx.conf.ServiceConfig.ReloadFile
	if f == "" {
		f = ".reload"
	}
	if f == "disabled" {
		return
	}
	for {
		// FIXME: File system notification rather than polling?
		time.Sleep(defaultRefreshPoll)
		if _, err := os.Stat(f); err == nil {
			if err := os.Remove(f); err == nil {
				ctx.logger.Printf("Reload requested")
				doStop(ctx)
				time.Sleep(time.Second)
				ctx.conf, _ = loadConf()
				doStart(ctx)
			}
		}
	}
}

func execStartupTasks(ctx *context) {
	for _, task := range ctx.conf.StartupTasks {
		runTask := func(task config.StartupTask) {
			defer ctx.runningGroup.Done()
			taskConfig := createTaskConfig(ctx, task.Task)
			if exitCode, err := svcutil.ExecuteTask(ctx.terminate, taskConfig); err != nil {
				ctx.logger.Printf("ERROR: Startup task '%s' reported: %v", taskConfig.Path, err)
			} else {
				ctx.logger.Printf("The task exits with exit code %d", exitCode)
			}
		}
		ctx.runningGroup.Add(1)
		if task.Async {
			if task.StartupDelaySecs > 0 || task.StartupRandomDelaySecs > 0 {
				ctx.logger.Printf("WARNING: Only Async startup tasks may have startup delays.")
			}
			go runTask(task)
		} else {
			runTask(task)
		}
	}
}

func startServices(ctx *context) {
	for _, service := range ctx.conf.Services {
		ctx.runningGroup.Add(1)
		go func(service config.Service) {
			defer ctx.runningGroup.Done()
			svcConfig := svcutil.ServiceConfig{}
			svcConfig.Path = service.Path
			svcConfig.Args = service.Args
			svcConfig.GracefulShutDown = time.Duration(service.GracefulShutdownTimeout) * time.Second
			svcConfig.StartupDelay = time.Duration(service.StartupDelaySecs) * time.Second
			svcConfig.Logger = ctx.logger
			svcConfig.CrashConfig = svcutil.CrashConfig{
				MaxCountPerHour: service.MaxCrashCount,
				RestartDelay:    time.Duration(service.RestartDelaySecs) * time.Second,
			}
			svcConfig.MonitorConfig = svcutil.MonitorConfig{
				URL:                   service.MonitorPing.URL,
				StartupDelay:          time.Duration(service.MonitorPing.StartupDelaySecs) * time.Second,
				Interval:              time.Duration(service.MonitorPing.IntervalSecs) * time.Second,
				Timeout:               time.Duration(service.MonitorPing.TimeoutSecs) * time.Second,
				RestartOnFailureCount: service.MonitorPing.RestartOnFailureCount,
			}
			if err := svcutil.ExecuteService(ctx.terminate, svcConfig); err != nil {
				ctx.logger.Printf("ERROR: Service '%s' reported: %v", service.Path, err)
			}
		}(service)
	}
}

func createTaskConfig(ctx *context, task config.Task) svcutil.TaskConfig {
	taskConfig := svcutil.TaskConfig{}
	taskConfig.Path = pathutils.FindLastFile(task.Path)
	taskConfig.Args = task.Args
	taskConfig.ExecTimeout = time.Duration(task.TimeoutSecs) * time.Second
	taskConfig.StartupDelay = time.Duration(task.StartupDelaySecs) * time.Second
	taskConfig.StartupRandomDelay = time.Duration(task.StartupRandomDelaySecs) * time.Second
	taskConfig.Logger = ctx.logger
	return taskConfig
}

func setupScheduledTasks(ctx *context) {
	ctx.cronManager = cron.New()
	for _, scheduledTask := range ctx.conf.ScheduledTasks {
		taskConfig := createTaskConfig(ctx, scheduledTask.Task)
		ctx.runningGroup.Add(1)
		runTask := func() {
			defer ctx.runningGroup.Done()
			if exitCode, err := svcutil.ExecuteTask(ctx.terminate, taskConfig); err != nil {
				ctx.logger.Printf("ERROR: scheduled task '%s' reported: %v", taskConfig.Path, err)
			} else {
				ctx.logger.Printf("The task exits with exit code %d", exitCode)
			}
		}
		err := ctx.cronManager.AddFunc(scheduledTask.Schedule, runTask)
		if err != nil {
			ctx.logger.Printf("Unable to schedule task '%s': %v", scheduledTask.Path, err)
		}
	}
	ctx.cronManager.Start()
}
<commit_msg>Fixed bugs<commit_after>// SILVER - Service Wrapper
//
// Copyright (c) 2014 PaperCut Software http://www.papercut.com/
// Use of this source code is governed by an MIT or GPL Version 2 license.
// See the project's LICENSE file for more information.
//
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sync"
	"time"

	"github.com/kardianos/service"

	"github.com/robfig/cron"

	"github.com/papercutsoftware/silver/lib/logging"
	"github.com/papercutsoftware/silver/lib/pathutils"
	"github.com/papercutsoftware/silver/service/cmdutil"
	"github.com/papercutsoftware/silver/service/config"
	"github.com/papercutsoftware/silver/service/svcutil"
)

const (
	defaultRefreshPoll = 10 * time.Second
)

type context struct {
	conf         *config.Config
	terminate    chan struct{}
	logger       *log.Logger
	runningGroup sync.WaitGroup
	cronManager  *cron.Cron
}

func main() {

	ctx := &context{
		terminate: make(chan struct{}),
	}

	// Parse config (we don't action any errors quite yet)
	var err error
	ctx.conf, err = loadConf()
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: Invalid config - %v\n", err)
		os.Exit(1)
	}

	action, actionArgs, err := parse(os.Args)
	if err != nil {
		printUsage(ctx.conf.ServiceDescription.DisplayName, ctx.conf.ServiceDescription.Description)
		os.Exit(1)
	}

	if err := os.Chdir(exeFolder()); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: Unable to set working directory - %v\n", err)
		os.Exit(1)
	}

	switch action {
	case "command":
		var cmdName string
		var cmdExtraArgs []string
		if len(actionArgs) >= 3 {
			cmdName = actionArgs[2]
		}
		if len(actionArgs) >= 4 {
			cmdExtraArgs = actionArgs[3:]
		}
		execCommand(ctx, cmdName, cmdExtraArgs)
	case "validate":
		fmt.Println("Config is valid")
		os.Exit(0)
	default:
		osServiceControl(ctx)
	}
}

func osServiceControl(ctx *context) {
	// Setup log file out
	logFile := ctx.conf.ServiceConfig.LogFile
	maxSize := int64(ctx.conf.ServiceConfig.LogFileMaxSizeMb) * 1024 * 1024
	if logFile == "" {
		logFile = serviceName() + ".log"
	}
	ctx.logger = logging.NewFileLoggerWithMaxSize(logFile, maxSize)

	// Setup service
	svcConfig := &service.Config{
		Name:        serviceName(),
		DisplayName: ctx.conf.ServiceDescription.DisplayName,
		Description: ctx.conf.ServiceDescription.Description,
	}

	osService := &osService{ctx: ctx}
	svc, err := service.New(osService, svcConfig)
	if err != nil {
		fmt.Printf("ERROR: Invalid service config: %v\n", err)
		os.Exit(1)
	}

	if len(os.Args) > 1 && os.Args[1] != "run" {
		err = service.Control(svc, os.Args[1])
		if err != nil {
			fmt.Printf("ERROR: Invalid service command: %v\n", err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	err = svc.Run()
	if err != nil {
		fmt.Printf("ERROR: %v\n", err)
		os.Exit(1)
	}

	pidFile := ctx.conf.ServiceConfig.PidFile
	if pidFile != "" {
		ioutil.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0644)
	}
}

func printUsage(svcDisplayName, svcDesc string) {
	fmt.Printf("%s (%s)\n", svcDisplayName,
		serviceName())
	fmt.Printf("%s\n\n", svcDesc)
	fmt.Printf("Usage:\n")
	fmt.Printf("%s [install|uninstall|start|stop|command|validate|run|help] [command-name]\n", exeName())
	fmt.Printf("  install   - Install the service.\n")
	fmt.Printf("  uninstall - Remove/uninstall the service.\n")
	fmt.Printf("  start     - Start an installed service.\n")
	fmt.Printf("  stop      - Stop an installed service.\n")
	fmt.Printf("  validate  - Test the configuration file.\n")
	fmt.Printf("  run       - Run service on in command-line mode.\n")
	fmt.Printf("  command   - Run a command [command-name].\n")
	fmt.Printf("  help      - This usage message.\n")
}

func loadConf() (conf *config.Config, err error) {
	// FIXME: Not Get this function out of utils.
	confPath := getConfigFilePath()
	vars := config.ReplacementVars{
		ServiceName: serviceName(),
		ServiceRoot: exeFolder(),
	}
	conf, err = config.LoadConfig(confPath, vars)
	if err != nil {
		return nil, err
	}

	// Merge in any include files
	for _, include := range conf.Include {
		conf, err = config.MergeInclude(*conf, include, vars)
		if err != nil {
			return nil, err
		}
	}
	return conf, err
}

func execCommand(ctx *context, cmdName string, cmdExtraArgs []string) {
	if len(ctx.conf.Commands) == 0 {
		fmt.Fprintf(os.Stderr, "There are no commands configured!\n")
		os.Exit(1)
	}
	var cmd *config.Command
	for _, c := range ctx.conf.Commands {
		if c.Name == cmdName {
			cmd = &c
			break
		}
	}

	if cmd == nil {
		fmt.Fprintf(os.Stderr, "Valid commands are:\n")
		for _, command := range ctx.conf.Commands {
			fmt.Fprintf(os.Stderr, "    %s\n", command.Name)
		}
		os.Exit(1)
	}

	cmdConf := cmdutil.CommandConfig{}
	cmdConf.Path = pathutils.FindLastFile(cmd.Path)
	cmdConf.Args = cmd.Args
	cmdConf.ExecTimeout = (time.Second * time.Duration(cmd.TimeoutSecs))

	exitCode, err := cmdutil.Execute(cmdConf)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
	}
	os.Exit(exitCode)
}

type osService struct {
	ctx *context
}

func (o *osService) Start(s service.Service) error {
	msg := fmt.Sprintf("Service '%s' started.", serviceName())
	o.ctx.logger.Printf(msg)
	sysLogger, err := s.Logger(nil)
	if err != nil {
		sysLogger.Info(msg)
	}

	doStart(o.ctx)
	go watchForReload(o.ctx)

	return nil
}

func doStart(ctx *context) {
	execStartupTasks(ctx)
	setupScheduledTasks(ctx)
	startServices(ctx)
}

func (o *osService) Stop(s service.Service) error {
	o.ctx.logger.Printf(fmt.Sprintf("Stopping '%s' service...", serviceName()))

	doStop(o.ctx)

	pidFile := o.ctx.conf.ServiceConfig.PidFile
	if pidFile != "" {
		os.Remove(pidFile)
	}

	msg := fmt.Sprintf("Stopped '%s' service.", serviceName())
	o.ctx.logger.Printf(msg)

	sysLogger, err := s.Logger(nil)
	if err != nil {
		sysLogger.Info(msg)
	}
	return nil
}

func doStop(ctx *context) {
	// Create stop file... another method to signal services to stop.
	stopFile := ctx.conf.ServiceConfig.StopFile
	if stopFile == "" {
		stopFile = ".stop"
	}
	if stopFile == "disabled" {
		return
	}
	ioutil.WriteFile(stopFile, nil, 0644)
	defer os.Remove(stopFile)
	if ctx.cronManager != nil {
		ctx.cronManager.Stop()
	}
	if ctx.terminate != nil {
		close(ctx.terminate)
	}
	ctx.runningGroup.Wait()
}

func watchForReload(ctx *context) {
	f := ctx.conf.ServiceConfig.ReloadFile
	if f == "" {
		f = ".reload"
	}
	if f == "disabled" {
		return
	}
	for {
		// FIXME: File system notification rather than polling?
		time.Sleep(defaultRefreshPoll)
		if _, err := os.Stat(f); err == nil {
			if err := os.Remove(f); err == nil {
				ctx.logger.Printf("Reload requested")
				doStop(ctx)
				time.Sleep(time.Second)
				ctx.conf, _ = loadConf()
				doStart(ctx)
			}
		}
	}
}

func execStartupTasks(ctx *context) {
	for _, task := range ctx.conf.StartupTasks {
		runTask := func(task config.StartupTask) {
			defer ctx.runningGroup.Done()
			taskConfig := createTaskConfig(ctx, task.Task)
			if exitCode, err := svcutil.ExecuteTask(ctx.terminate, taskConfig); err != nil {
				ctx.logger.Printf("ERROR: Startup task '%s' reported: %v", taskConfig.Path, err)
			} else {
				ctx.logger.Printf("The task exits with exit code %d", exitCode)
			}
		}
		ctx.runningGroup.Add(1)
		if task.Async {
			go runTask(task)
		} else {
			if task.StartupDelaySecs > 0 || task.StartupRandomDelaySecs > 0 {
				ctx.logger.Printf("WARNING: Only Async startup tasks should have startup delays.")
			}
			runTask(task)
		}
	}
}

func startServices(ctx *context) {
	for _, service := range ctx.conf.Services {
		ctx.runningGroup.Add(1)
		go func(service config.Service) {
			defer ctx.runningGroup.Done()
			svcConfig := svcutil.ServiceConfig{}
			svcConfig.Path = service.Path
			svcConfig.Args = service.Args
			svcConfig.GracefulShutDown = time.Duration(service.GracefulShutdownTimeout) * time.Second
			svcConfig.StartupDelay = time.Duration(service.StartupDelaySecs) * time.Second
			svcConfig.Logger = ctx.logger
			svcConfig.CrashConfig = svcutil.CrashConfig{
				MaxCountPerHour: service.MaxCrashCount,
				RestartDelay:    time.Duration(service.RestartDelaySecs) * time.Second,
			}
			if service.MonitorPing != nil {
				svcConfig.MonitorConfig = svcutil.MonitorConfig{
					URL:                   service.MonitorPing.URL,
					StartupDelay:          time.Duration(service.MonitorPing.StartupDelaySecs) * time.Second,
					Interval:              time.Duration(service.MonitorPing.IntervalSecs) * time.Second,
					Timeout:               time.Duration(service.MonitorPing.TimeoutSecs) * time.Second,
					RestartOnFailureCount: service.MonitorPing.RestartOnFailureCount,
				}
			}
			if err := svcutil.ExecuteService(ctx.terminate, svcConfig); err != nil {
				ctx.logger.Printf("ERROR: Service '%s' reported: %v", service.Path, err)
			}
		}(service)
	}
}

func createTaskConfig(ctx *context, task config.Task) svcutil.TaskConfig {
	taskConfig := svcutil.TaskConfig{}
	taskConfig.Path = pathutils.FindLastFile(task.Path)
	taskConfig.Args = task.Args
	taskConfig.ExecTimeout = time.Duration(task.TimeoutSecs) * time.Second
	taskConfig.StartupDelay = time.Duration(task.StartupDelaySecs) * time.Second
	taskConfig.StartupRandomDelay = time.Duration(task.StartupRandomDelaySecs) * time.Second
	taskConfig.Logger = ctx.logger
	return taskConfig
}

func setupScheduledTasks(ctx *context) {
	ctx.cronManager = cron.New()
	for _, scheduledTask := range ctx.conf.ScheduledTasks {
		taskConfig := createTaskConfig(ctx, scheduledTask.Task)
		ctx.runningGroup.Add(1)
		runTask := func() {
			defer ctx.runningGroup.Done()
			if exitCode, err := svcutil.ExecuteTask(ctx.terminate, taskConfig); err != nil {
				ctx.logger.Printf("ERROR: scheduled task '%s' reported: %v", taskConfig.Path, err)
			} else {
				ctx.logger.Printf("The task exits with exit code %d", exitCode)
			}
		}
		err := ctx.cronManager.AddFunc(scheduledTask.Schedule, runTask)
		if err != nil {
			ctx.logger.Printf("Unable to schedule task '%s': %v", scheduledTask.Path, err)
		}
	}
	ctx.cronManager.Start()
}
<|endoftext|>


<commit_before>package gomoku

//記録用
type Record struct {
	turns []int
	x     []int
	y     []int
}

func NewRecord() *Record {
	return &Record{
		turns: make([]int, 0),
		x:     make([]int, 0),
		y:     make([]int, 0),
	}
}

func (r *Record) Push(turn, x, y int) {
	r.turns = append(r.turns, turn)
	r.x = append(r.x, x)
	r.y = append(r.y, y)
}

func (r *Record) LastX() int {
	return r.x[len(r.x)-1]
}

func (r *Record) LastY() int {
	return r.y[len(r.y)-1]
}

func (r *Record) Winner() int {
	return r.turns[len(r.turns)-1]
}
<commit_msg>ちょこっと修正<commit_after>package gomoku

//記録用
type Record struct {
	turns []int
	x     []int
	y     []int
}

func NewRecord() *Record {
	return &Record{
		turns: make([]int, 0),
		x:     make([]int, 0),
		y:     make([]int, 0),
	}
}

func (r *Record) Push(turn, x, y int) {
	r.turns = append(r.turns, turn)
	r.x = append(r.x, x)
	r.y = append(r.y, y)
}

func (r *Record) Last() (int, int) {
	return r.x[len(r.x)-1], r.y[len(r.y)-1]
}

func (r *Record) Winner() int {
	return r.turns[len(r.turns)-1]
}
<|endoftext|>


<commit_before>/* {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE. }}} */

package archive

import (
	"fmt"
	"io"
	"os"
	"strconv"

	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"hash"

	"pault.ag/go/debian/control"
	"pault.ag/go/debian/deb"
	"pault.ag/go/debian/dependency"
	"pault.ag/go/debian/version"
)

// Package {{{

// Binary .deb Package entry, as it exists in the Packages file, which
// contains the .deb Control information, as well as information on
// where the file lives, the file size, and some hashes.
type Package struct {
	control.Paragraph

	Package       string `required:"true"`
	Source        string
	Version       version.Version `required:"true"`
	Section       string
	Priority      string
	Architecture  dependency.Arch `required:"true"`
	Essential     string
	InstalledSize int    `control:"Installed-Size"`
	Maintainer    string `required:"true"`
	Description   string `required:"true"`
	Homepage      string

	Filename       string `required:"true"`
	Size           int    `required:"true"`
	MD5sum         string
	SHA1           string
	SHA256         string
	DescriptionMD5 string `control:"Description-md5"`
}

// PackageFromDeb {{{

// Create a Package entry from a deb.Deb file. This will copy the binary
// .deb Control file into the Package entry, and set information as to
// the location of the file, the size of the file, and hash the file.
func PackageFromDeb(debFile deb.Deb) (*Package, error) {
	pkg := Package{}

	paragraph := debFile.Control.Paragraph
	paragraph.Set("Filename", debFile.Path)
	/* Now, let's do some magic */

	fd, err := os.Open(debFile.Path)
	if err != nil {
		return nil, err
	}
	stat, err := fd.Stat()
	if err != nil {
		return nil, err
	}
	paragraph.Set("Size", strconv.Itoa(int(stat.Size())))
	/* Right, now, in addition, we ought to hash the crap out of the file */

	for key, hasher := range map[string]hash.Hash{
		"MD5sum": md5.New(),
		"SHA1":   sha1.New(),
		"SHA256": sha256.New(),
	} {
		fd, err := os.Open(debFile.Path)
		if err != nil {
			return nil, err
		}
		/* XXX: Fix this to stream to all the hashing at once */
		if _, err := io.Copy(hasher, fd); err != nil {
			return nil, err
		}
		paragraph.Set(key, fmt.Sprintf("%x", hasher.Sum(nil)))
	}

	return &pkg, control.UnpackFromParagraph(debFile.Control.Paragraph, &pkg)
}

// }}}

// }}}

// Packages {{{

// Iterator to access the entries contained in the Packages entry in an
// apt repo. This contians information about the binary Debian packages.
type Packages struct {
	decoder *control.Decoder
}

// Next {{{

// Get the next Package entry in the Packages list. This will return an
// io.EOF at the last entry.
func (p *Packages) Next() (*Package, error) {
	next := Package{}
	return &next, p.decoder.Decode(&next)
}

// }}}

// LoadPackagesFile {{{

// Given a path, create a Packages iterator. Note that the Packages
// file is not OpenPGP signed, so one will need to verify the integrety
// of this file from the InRelease file before trusting any output.
func LoadPackagesFile(path string) (*Packages, error) {
	fd, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	return LoadPackages(fd)
}

// }}}

// LoadPackages {{{

// Given an io.Reader, create a Packages iterator. Note that the Packages
// file is not OpenPGP signed, so one will need to verify the integrety
// of this file from the InRelease file before trusting any output.
func LoadPackages(in io.Reader) (*Packages, error) {
	decoder, err := control.NewDecoder(in, nil)
	if err != nil {
		return nil, err
	}
	return &Packages{decoder: decoder}, nil
}

// }}}

// }}}

// vim: foldmethod=marker
<commit_msg>only write once<commit_after>/* {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE. }}} */

package archive

import (
	"fmt"
	"io"
	"os"
	"strconv"

	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"hash"

	"pault.ag/go/debian/control"
	"pault.ag/go/debian/deb"
	"pault.ag/go/debian/dependency"
	"pault.ag/go/debian/version"
)

// Package {{{

// Binary .deb Package entry, as it exists in the Packages file, which
// contains the .deb Control information, as well as information on
// where the file lives, the file size, and some hashes.
type Package struct {
	control.Paragraph

	Package       string `required:"true"`
	Source        string
	Version       version.Version `required:"true"`
	Section       string
	Priority      string
	Architecture  dependency.Arch `required:"true"`
	Essential     string
	InstalledSize int    `control:"Installed-Size"`
	Maintainer    string `required:"true"`
	Description   string `required:"true"`
	Homepage      string

	Filename       string `required:"true"`
	Size           int    `required:"true"`
	MD5sum         string
	SHA1           string
	SHA256         string
	DescriptionMD5 string `control:"Description-md5"`
}

// PackageFromDeb {{{

// Create a Package entry from a deb.Deb file. This will copy the binary
// .deb Control file into the Package entry, and set information as to
// the location of the file, the size of the file, and hash the file.
func PackageFromDeb(debFile deb.Deb) (*Package, error) {
	pkg := Package{}

	paragraph := debFile.Control.Paragraph
	paragraph.Set("Filename", debFile.Path)
	/* Now, let's do some magic */

	fd, err := os.Open(debFile.Path)
	if err != nil {
		return nil, err
	}
	stat, err := fd.Stat()
	if err != nil {
		return nil, err
	}

	paragraph.Set("Size", strconv.Itoa(int(stat.Size())))
	/* Right, now, in addition, we ought to hash the crap out of the file */

	md5sum := md5.New()
	sha1 := sha1.New()
	sha256 := sha256.New()

	writer := io.MultiWriter(md5sum, sha256, sha1)

	if _, err := io.Copy(writer, fd); err != nil {
		return nil, err
	}

	for key, hasher := range map[string]hash.Hash{
		"MD5sum": md5sum,
		"SHA1":   sha1,
		"SHA256": sha256,
	} {
		paragraph.Set(key, fmt.Sprintf("%x", hasher.Sum(nil)))
	}

	return &pkg, control.UnpackFromParagraph(debFile.Control.Paragraph, &pkg)
}

// }}}

// }}}

// Packages {{{

// Iterator to access the entries contained in the Packages entry in an
// apt repo. This contians information about the binary Debian packages.
type Packages struct {
	decoder *control.Decoder
}

// Next {{{

// Get the next Package entry in the Packages list. This will return an
// io.EOF at the last entry.
func (p *Packages) Next() (*Package, error) {
	next := Package{}
	return &next, p.decoder.Decode(&next)
}

// }}}

// LoadPackagesFile {{{

// Given a path, create a Packages iterator. Note that the Packages
// file is not OpenPGP signed, so one will need to verify the integrety
// of this file from the InRelease file before trusting any output.
func LoadPackagesFile(path string) (*Packages, error) {
	fd, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	return LoadPackages(fd)
}

// }}}

// LoadPackages {{{

// Given an io.Reader, create a Packages iterator. Note that the Packages
// file is not OpenPGP signed, so one will need to verify the integrety
// of this file from the InRelease file before trusting any output.
func LoadPackages(in io.Reader) (*Packages, error) {
	decoder, err := control.NewDecoder(in, nil)
	if err != nil {
		return nil, err
	}
	return &Packages{decoder: decoder}, nil
}

// }}}

// }}}

// vim: foldmethod=marker
<|endoftext|>


<commit_before>package commands

import (
	"errors"
	"io"

	cmds "github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/filestore"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
)

type chanWriter struct {
	ch     <-chan *filestore.ListRes
	buf    string
	offset int
}

func (w *chanWriter) Read(p []byte) (int, error) {
	if w.offset >= len(w.buf) {
		w.offset = 0
		res, more := <-w.ch
		if !more {
			return 0, io.EOF
		}
		w.buf = res.Format()
	}
	sz := copy(p, w.buf[w.offset:])
	w.offset += sz
	return sz, nil
}

var FileStoreCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Interact with filestore objects",
	},
	Subcommands: map[string]*cmds.Command{
		"ls":     lsFileStore,
		"verify": verifyFileStore,
	},
}

var lsFileStore = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "List objects on filestore",
	},

	Run: func(req cmds.Request, res cmds.Response) {
		_, fs, err := extractFilestore(req)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		ch := make(chan *filestore.ListRes)
		go func() {
			defer close(ch)
			filestore.List(fs, ch)
		}()
		res.SetOutput(&chanWriter{ch, "", 0})
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			return res.(io.Reader), nil
		},
	},
}

var verifyFileStore = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Verify objects in filestore",
	},

	Run: func(req cmds.Request, res cmds.Response) {
		_, fs, err := extractFilestore(req)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		ch := make(chan *filestore.ListRes)
		go func() {
			defer close(ch)
			filestore.Verify(fs, ch)
		}()
		res.SetOutput(&chanWriter{ch, "", 0})
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			return res.(io.Reader), nil
		},
	},
}

func extractFilestore(req cmds.Request) (node *core.IpfsNode, fs *filestore.Datastore, err error) {
	node, err = req.InvocContext().GetNode()
	if err != nil {
		return
	}
	repo, ok := node.Repo.Self().(*fsrepo.FSRepo)
	if !ok {
		err = errors.New("Not a FSRepo")
		return
	}
	fs = repo.Filestore()
	return
}
<commit_msg>Add temp. utility command to find dangling pins.<commit_after>package commands

import (
	"errors"
	"fmt"
	"io"

	bs "github.com/ipfs/go-ipfs/blocks/blockstore"
	k "github.com/ipfs/go-ipfs/blocks/key"
	cmds "github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/filestore"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
)

type chanWriter struct {
	ch     <-chan *filestore.ListRes
	buf    string
	offset int
}

func (w *chanWriter) Read(p []byte) (int, error) {
	if w.offset >= len(w.buf) {
		w.offset = 0
		res, more := <-w.ch
		if !more {
			return 0, io.EOF
		}
		w.buf = res.Format()
	}
	sz := copy(p, w.buf[w.offset:])
	w.offset += sz
	return sz, nil
}

var FileStoreCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Interact with filestore objects",
	},
	Subcommands: map[string]*cmds.Command{
		"ls":                 lsFileStore,
		"verify":             verifyFileStore,
		"find-dangling-pins": findDanglingPins,
	},
}

var lsFileStore = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "List objects on filestore",
	},

	Run: func(req cmds.Request, res cmds.Response) {
		_, fs, err := extractFilestore(req)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		ch := make(chan *filestore.ListRes)
		go func() {
			defer close(ch)
			filestore.List(fs, ch)
		}()
		res.SetOutput(&chanWriter{ch, "", 0})
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			return res.(io.Reader), nil
		},
	},
}

var verifyFileStore = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Verify objects in filestore",
	},

	Run: func(req cmds.Request, res cmds.Response) {
		_, fs, err := extractFilestore(req)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		ch := make(chan *filestore.ListRes)
		go func() {
			defer close(ch)
			filestore.Verify(fs, ch)
		}()
		res.SetOutput(&chanWriter{ch, "", 0})
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			return res.(io.Reader), nil
		},
	},
}

func extractFilestore(req cmds.Request) (node *core.IpfsNode, fs *filestore.Datastore, err error) {
	node, err = req.InvocContext().GetNode()
	if err != nil {
		return
	}
	repo, ok := node.Repo.Self().(*fsrepo.FSRepo)
	if !ok {
		err = errors.New("Not a FSRepo")
		return
	}
	fs = repo.Filestore()
	return
}

var findDanglingPins = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "List pinned objects that no longer exists",
	},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			return
		}
		r, w := io.Pipe()
		go func() {
			defer w.Close()
			err := listDanglingPins(n.Pinning.DirectKeys(), w, n.Blockstore)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			err = listDanglingPins(n.Pinning.RecursiveKeys(), w, n.Blockstore)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}()
		res.SetOutput(r)
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			return res.(io.Reader), nil
		},
	},
}

func listDanglingPins(keys []k.Key, out io.Writer, d bs.Blockstore) error {
	for _, k := range keys {
		exists, err := d.Has(k)
		if err != nil {
			return err
		}
		if !exists {
			fmt.Fprintln(out, k.B58String())
		}
	}
	return nil
}
<|endoftext|>


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

// Values
//
// All interpreter values are "boxed" in the empty interface, value.
// The range of possible dynamic types within value are:
//
// - bool
// - numbers (all built-in int/float/complex types are distinguished)
// - string
// - map[value]value --- maps for which  usesBuiltinMap(keyType)
//   *hashmap        --- maps for which !usesBuiltinMap(keyType)
// - chan value
// - []value --- slices
// - iface --- interfaces.
// - structure --- structs.  Fields are ordered and accessed by numeric indices.
// - array --- arrays.
// - *value --- pointers.  Careful: *value is a distinct type from *array etc.
// - *ssa.Function \
//   *ssa.Builtin   } --- functions.  A nil 'func' is always of type *ssa.Function.
//   *closure      /
// - tuple --- as returned by Return, Next, "value,ok" modes, etc.
// - iter --- iterators from 'range' over map or string.
// - bad --- a poison pill for locals that have gone out of scope.
// - rtype -- the interpreter's concrete implementation of reflect.Type
//
// Note that nil is not on this list.
//
// Pay close attention to whether or not the dynamic type is a pointer.
// The compiler cannot help you since value is an empty interface.

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"strings"
	"sync"
	"unsafe"

	"code.google.com/p/go.tools/go/types"
	"code.google.com/p/go.tools/go/types/typemap"
	"code.google.com/p/go.tools/ssa"
)

type value interface{}

type tuple []value

type array []value

type iface struct {
	t types.Type // never an "untyped" type
	v value
}

type structure []value

// For map, array, *array, slice, string or channel.
type iter interface {
	// next returns a Tuple (key, value, ok).
	// key and value are unaliased, e.g. copies of the sequence element.
	next() tuple
}

type closure struct {
	Fn  *ssa.Function
	Env []value
}

type bad struct{}

type rtype struct {
	t types.Type
}

// Hash functions and equivalence relation:

// hashString computes the FNV hash of s.
func hashString(s string) int {
	var h uint32
	for i := 0; i < len(s); i++ {
		h ^= uint32(s[i])
		h *= 16777619
	}
	return int(h)
}

var (
	mu     sync.Mutex
	hasher = typemap.MakeHasher()
)

// hashType returns a hash for t such that
// types.IsIdentical(x, y) => hashType(x) == hashType(y).
func hashType(t types.Type) int {
	mu.Lock()
	h := int(hasher.Hash(t))
	mu.Unlock()
	return h
}

// usesBuiltinMap returns true if the built-in hash function and
// equivalence relation for type t are consistent with those of the
// interpreter's representation of type t.  Such types are: all basic
// types (bool, numbers, string), pointers and channels.
//
// usesBuiltinMap returns false for types that require a custom map
// implementation: interfaces, arrays and structs.
//
// Panic ensues if t is an invalid map key type: function, map or slice.
func usesBuiltinMap(t types.Type) bool {
	switch t := t.(type) {
	case *types.Basic, *types.Chan, *types.Pointer:
		return true
	case *types.Named:
		return usesBuiltinMap(t.Underlying())
	case *types.Interface, *types.Array, *types.Struct:
		return false
	}
	panic(fmt.Sprintf("invalid map key type: %T", t))
}

func (x array) eq(t types.Type, _y interface{}) bool {
	y := _y.(array)
	tElt := t.Underlying().(*types.Array).Elem()
	for i, xi := range x {
		if !equals(tElt, xi, y[i]) {
			return false
		}
	}
	return true
}

func (x array) hash(t types.Type) int {
	h := 0
	tElt := t.Underlying().(*types.Array).Elem()
	for _, xi := range x {
		h += hash(tElt, xi)
	}
	return h
}

func (x structure) eq(t types.Type, _y interface{}) bool {
	y := _y.(structure)
	tStruct := t.Underlying().(*types.Struct)
	for i, n := 0, tStruct.NumFields(); i < n; i++ {
		if f := tStruct.Field(i); !f.Anonymous() {
			if !equals(f.Type(), x[i], y[i]) {
				return false
			}
		}
	}
	return true
}

func (x structure) hash(t types.Type) int {
	tStruct := t.Underlying().(*types.Struct)
	h := 0
	for i, n := 0, tStruct.NumFields(); i < n; i++ {
		if f := tStruct.Field(i); !f.Anonymous() {
			h += hash(f.Type(), x[i])
		}
	}
	return h
}

func (x iface) eq(t types.Type, _y interface{}) bool {
	y := _y.(iface)
	return types.IsIdentical(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v))
}

func (x iface) hash(_ types.Type) int {
	return hashType(x.t)*8581 + hash(x.t, x.v)
}

func (x rtype) hash(_ types.Type) int {
	return hashType(x.t)
}

func (x rtype) eq(_ types.Type, y interface{}) bool {
	return types.IsIdentical(x.t, y.(rtype).t)
}

// equals returns true iff x and y are equal according to Go's
// linguistic equivalence relation for type t.
// In a well-typed program, the dynamic types of x and y are
// guaranteed equal.
func equals(t types.Type, x, y value) bool {
	switch x := x.(type) {
	case bool:
		return x == y.(bool)
	case int:
		return x == y.(int)
	case int8:
		return x == y.(int8)
	case int16:
		return x == y.(int16)
	case int32:
		return x == y.(int32)
	case int64:
		return x == y.(int64)
	case uint:
		return x == y.(uint)
	case uint8:
		return x == y.(uint8)
	case uint16:
		return x == y.(uint16)
	case uint32:
		return x == y.(uint32)
	case uint64:
		return x == y.(uint64)
	case uintptr:
		return x == y.(uintptr)
	case float32:
		return x == y.(float32)
	case float64:
		return x == y.(float64)
	case complex64:
		return x == y.(complex64)
	case complex128:
		return x == y.(complex128)
	case string:
		return x == y.(string)
	case *value:
		return x == y.(*value)
	case chan value:
		return x == y.(chan value)
	case structure:
		return x.eq(t, y)
	case array:
		return x.eq(t, y)
	case iface:
		return x.eq(t, y)
	case rtype:
		return x.eq(t, y)
	}

	// Since map, func and slice don't support comparison, this
	// case is only reachable if one of x or y is literally nil
	// (handled in eqnil) or via interface{} values.
	panic(fmt.Sprintf("comparing uncomparable type %s", t))
}

// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
func hash(t types.Type, x value) int {
	switch x := x.(type) {
	case bool:
		if x {
			return 1
		}
		return 0
	case int:
		return x
	case int8:
		return int(x)
	case int16:
		return int(x)
	case int32:
		return int(x)
	case int64:
		return int(x)
	case uint:
		return int(x)
	case uint8:
		return int(x)
	case uint16:
		return int(x)
	case uint32:
		return int(x)
	case uint64:
		return int(x)
	case uintptr:
		return int(x)
	case float32:
		return int(x)
	case float64:
		return int(x)
	case complex64:
		return int(real(x))
	case complex128:
		return int(real(x))
	case string:
		return hashString(x)
	case *value:
		return int(uintptr(unsafe.Pointer(x)))
	case chan value:
		return int(uintptr(reflect.ValueOf(x).Pointer()))
	case structure:
		return x.hash(t)
	case array:
		return x.hash(t)
	case iface:
		return x.hash(t)
	case rtype:
		return x.hash(t)
	}
	panic(fmt.Sprintf("%T is unhashable", x))
}

// copyVal returns a copy of value v.
// TODO(adonovan): add tests of aliasing and mutation.
func copyVal(v value) value {
	if v == nil {
		panic("copyVal(nil)")
	}
	switch v := v.(type) {
	case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string, unsafe.Pointer:
		return v
	case map[value]value:
		return v
	case *hashmap:
		return v
	case chan value:
		return v
	case *value:
		return v
	case *ssa.Function, *ssa.Builtin, *closure:
		return v
	case iface:
		return v
	case []value:
		return v
	case structure:
		a := make(structure, len(v))
		copy(a, v)
		return a
	case array:
		a := make(array, len(v))
		copy(a, v)
		return a
	case tuple:
		break
	case rtype:
		return v
	}
	panic(fmt.Sprintf("cannot copy %T", v))
}

// Prints in the style of built-in println.
// (More or less; in gc println is actually a compiler intrinsic and
// can distinguish println(1) from println(interface{}(1)).)
func toWriter(w io.Writer, v value) {
	switch v := v.(type) {
	case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
		fmt.Fprintf(w, "%v", v)

	case map[value]value:
		io.WriteString(w, "map[")
		sep := " "
		for k, e := range v {
			io.WriteString(w, sep)
			sep = " "
			toWriter(w, k)
			io.WriteString(w, ":")
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case *hashmap:
		io.WriteString(w, "map[")
		sep := " "
		for _, e := range v.table {
			for e != nil {
				io.WriteString(w, sep)
				sep = " "
				toWriter(w, e.key)
				io.WriteString(w, ":")
				toWriter(w, e.value)
				e = e.next
			}
		}
		io.WriteString(w, "]")

	case chan value:
		fmt.Fprintf(w, "%v", v) // (an address)

	case *value:
		if v == nil {
			io.WriteString(w, "<nil>")
		} else {
			fmt.Fprintf(w, "%p", v)
		}

	case iface:
		toWriter(w, v.v)

	case structure:
		io.WriteString(w, "{")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "}")

	case array:
		io.WriteString(w, "[")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case []value:
		io.WriteString(w, "[")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case *ssa.Function, *ssa.Builtin, *closure:
		fmt.Fprintf(w, "%p", v) // (an address)

	case rtype:
		io.WriteString(w, v.t.String())

	case tuple:
		// Unreachable in well-formed Go programs
		io.WriteString(w, "(")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, ", ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, ")")

	default:
		fmt.Fprintf(w, "<%T>", v)
	}
}

// Implements printing of Go values in the style of built-in println.
func toString(v value) string {
	var b bytes.Buffer
	toWriter(&b, v)
	return b.String()
}

// ------------------------------------------------------------------------
// Iterators

type stringIter struct {
	*strings.Reader
	i int
}

func (it *stringIter) next() tuple {
	okv := make(tuple, 3)
	ch, n, err := it.ReadRune()
	ok := err != io.EOF
	okv[0] = ok
	if ok {
		okv[1] = it.i
		okv[2] = ch
	}
	it.i += n
	return okv
}

type mapIter chan [2]value

func (it mapIter) next() tuple {
	kv, ok := <-it
	return tuple{ok, kv[0], kv[1]}
}
<commit_msg>go/tools/ssa/interp: make iface.eq robust against nil types<commit_after>// Copyright 2013 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 interp

// Values
//
// All interpreter values are "boxed" in the empty interface, value.
// The range of possible dynamic types within value are:
//
// - bool
// - numbers (all built-in int/float/complex types are distinguished)
// - string
// - map[value]value --- maps for which  usesBuiltinMap(keyType)
//   *hashmap        --- maps for which !usesBuiltinMap(keyType)
// - chan value
// - []value --- slices
// - iface --- interfaces.
// - structure --- structs.  Fields are ordered and accessed by numeric indices.
// - array --- arrays.
// - *value --- pointers.  Careful: *value is a distinct type from *array etc.
// - *ssa.Function \
//   *ssa.Builtin   } --- functions.  A nil 'func' is always of type *ssa.Function.
//   *closure      /
// - tuple --- as returned by Return, Next, "value,ok" modes, etc.
// - iter --- iterators from 'range' over map or string.
// - bad --- a poison pill for locals that have gone out of scope.
// - rtype -- the interpreter's concrete implementation of reflect.Type
//
// Note that nil is not on this list.
//
// Pay close attention to whether or not the dynamic type is a pointer.
// The compiler cannot help you since value is an empty interface.

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"strings"
	"sync"
	"unsafe"

	"code.google.com/p/go.tools/go/types"
	"code.google.com/p/go.tools/go/types/typemap"
	"code.google.com/p/go.tools/ssa"
)

type value interface{}

type tuple []value

type array []value

type iface struct {
	t types.Type // never an "untyped" type
	v value
}

type structure []value

// For map, array, *array, slice, string or channel.
type iter interface {
	// next returns a Tuple (key, value, ok).
	// key and value are unaliased, e.g. copies of the sequence element.
	next() tuple
}

type closure struct {
	Fn  *ssa.Function
	Env []value
}

type bad struct{}

type rtype struct {
	t types.Type
}

// Hash functions and equivalence relation:

// hashString computes the FNV hash of s.
func hashString(s string) int {
	var h uint32
	for i := 0; i < len(s); i++ {
		h ^= uint32(s[i])
		h *= 16777619
	}
	return int(h)
}

var (
	mu     sync.Mutex
	hasher = typemap.MakeHasher()
)

// hashType returns a hash for t such that
// types.IsIdentical(x, y) => hashType(x) == hashType(y).
func hashType(t types.Type) int {
	mu.Lock()
	h := int(hasher.Hash(t))
	mu.Unlock()
	return h
}

// usesBuiltinMap returns true if the built-in hash function and
// equivalence relation for type t are consistent with those of the
// interpreter's representation of type t.  Such types are: all basic
// types (bool, numbers, string), pointers and channels.
//
// usesBuiltinMap returns false for types that require a custom map
// implementation: interfaces, arrays and structs.
//
// Panic ensues if t is an invalid map key type: function, map or slice.
func usesBuiltinMap(t types.Type) bool {
	switch t := t.(type) {
	case *types.Basic, *types.Chan, *types.Pointer:
		return true
	case *types.Named:
		return usesBuiltinMap(t.Underlying())
	case *types.Interface, *types.Array, *types.Struct:
		return false
	}
	panic(fmt.Sprintf("invalid map key type: %T", t))
}

func (x array) eq(t types.Type, _y interface{}) bool {
	y := _y.(array)
	tElt := t.Underlying().(*types.Array).Elem()
	for i, xi := range x {
		if !equals(tElt, xi, y[i]) {
			return false
		}
	}
	return true
}

func (x array) hash(t types.Type) int {
	h := 0
	tElt := t.Underlying().(*types.Array).Elem()
	for _, xi := range x {
		h += hash(tElt, xi)
	}
	return h
}

func (x structure) eq(t types.Type, _y interface{}) bool {
	y := _y.(structure)
	tStruct := t.Underlying().(*types.Struct)
	for i, n := 0, tStruct.NumFields(); i < n; i++ {
		if f := tStruct.Field(i); !f.Anonymous() {
			if !equals(f.Type(), x[i], y[i]) {
				return false
			}
		}
	}
	return true
}

func (x structure) hash(t types.Type) int {
	tStruct := t.Underlying().(*types.Struct)
	h := 0
	for i, n := 0, tStruct.NumFields(); i < n; i++ {
		if f := tStruct.Field(i); !f.Anonymous() {
			h += hash(f.Type(), x[i])
		}
	}
	return h
}

// nil-tolerant variant of types.IsIdentical.
func sameType(x, y types.Type) bool {
	if x == nil {
		return y == nil
	}
	return y != nil && types.IsIdentical(x, y)
}

func (x iface) eq(t types.Type, _y interface{}) bool {
	y := _y.(iface)
	return sameType(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v))
}

func (x iface) hash(_ types.Type) int {
	return hashType(x.t)*8581 + hash(x.t, x.v)
}

func (x rtype) hash(_ types.Type) int {
	return hashType(x.t)
}

func (x rtype) eq(_ types.Type, y interface{}) bool {
	return types.IsIdentical(x.t, y.(rtype).t)
}

// equals returns true iff x and y are equal according to Go's
// linguistic equivalence relation for type t.
// In a well-typed program, the dynamic types of x and y are
// guaranteed equal.
func equals(t types.Type, x, y value) bool {
	switch x := x.(type) {
	case bool:
		return x == y.(bool)
	case int:
		return x == y.(int)
	case int8:
		return x == y.(int8)
	case int16:
		return x == y.(int16)
	case int32:
		return x == y.(int32)
	case int64:
		return x == y.(int64)
	case uint:
		return x == y.(uint)
	case uint8:
		return x == y.(uint8)
	case uint16:
		return x == y.(uint16)
	case uint32:
		return x == y.(uint32)
	case uint64:
		return x == y.(uint64)
	case uintptr:
		return x == y.(uintptr)
	case float32:
		return x == y.(float32)
	case float64:
		return x == y.(float64)
	case complex64:
		return x == y.(complex64)
	case complex128:
		return x == y.(complex128)
	case string:
		return x == y.(string)
	case *value:
		return x == y.(*value)
	case chan value:
		return x == y.(chan value)
	case structure:
		return x.eq(t, y)
	case array:
		return x.eq(t, y)
	case iface:
		return x.eq(t, y)
	case rtype:
		return x.eq(t, y)
	}

	// Since map, func and slice don't support comparison, this
	// case is only reachable if one of x or y is literally nil
	// (handled in eqnil) or via interface{} values.
	panic(fmt.Sprintf("comparing uncomparable type %s", t))
}

// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
func hash(t types.Type, x value) int {
	switch x := x.(type) {
	case bool:
		if x {
			return 1
		}
		return 0
	case int:
		return x
	case int8:
		return int(x)
	case int16:
		return int(x)
	case int32:
		return int(x)
	case int64:
		return int(x)
	case uint:
		return int(x)
	case uint8:
		return int(x)
	case uint16:
		return int(x)
	case uint32:
		return int(x)
	case uint64:
		return int(x)
	case uintptr:
		return int(x)
	case float32:
		return int(x)
	case float64:
		return int(x)
	case complex64:
		return int(real(x))
	case complex128:
		return int(real(x))
	case string:
		return hashString(x)
	case *value:
		return int(uintptr(unsafe.Pointer(x)))
	case chan value:
		return int(uintptr(reflect.ValueOf(x).Pointer()))
	case structure:
		return x.hash(t)
	case array:
		return x.hash(t)
	case iface:
		return x.hash(t)
	case rtype:
		return x.hash(t)
	}
	panic(fmt.Sprintf("%T is unhashable", x))
}

// copyVal returns a copy of value v.
// TODO(adonovan): add tests of aliasing and mutation.
func copyVal(v value) value {
	if v == nil {
		panic("copyVal(nil)")
	}
	switch v := v.(type) {
	case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string, unsafe.Pointer:
		return v
	case map[value]value:
		return v
	case *hashmap:
		return v
	case chan value:
		return v
	case *value:
		return v
	case *ssa.Function, *ssa.Builtin, *closure:
		return v
	case iface:
		return v
	case []value:
		return v
	case structure:
		a := make(structure, len(v))
		copy(a, v)
		return a
	case array:
		a := make(array, len(v))
		copy(a, v)
		return a
	case tuple:
		break
	case rtype:
		return v
	}
	panic(fmt.Sprintf("cannot copy %T", v))
}

// Prints in the style of built-in println.
// (More or less; in gc println is actually a compiler intrinsic and
// can distinguish println(1) from println(interface{}(1)).)
func toWriter(w io.Writer, v value) {
	switch v := v.(type) {
	case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
		fmt.Fprintf(w, "%v", v)

	case map[value]value:
		io.WriteString(w, "map[")
		sep := " "
		for k, e := range v {
			io.WriteString(w, sep)
			sep = " "
			toWriter(w, k)
			io.WriteString(w, ":")
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case *hashmap:
		io.WriteString(w, "map[")
		sep := " "
		for _, e := range v.table {
			for e != nil {
				io.WriteString(w, sep)
				sep = " "
				toWriter(w, e.key)
				io.WriteString(w, ":")
				toWriter(w, e.value)
				e = e.next
			}
		}
		io.WriteString(w, "]")

	case chan value:
		fmt.Fprintf(w, "%v", v) // (an address)

	case *value:
		if v == nil {
			io.WriteString(w, "<nil>")
		} else {
			fmt.Fprintf(w, "%p", v)
		}

	case iface:
		toWriter(w, v.v)

	case structure:
		io.WriteString(w, "{")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "}")

	case array:
		io.WriteString(w, "[")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case []value:
		io.WriteString(w, "[")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, " ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, "]")

	case *ssa.Function, *ssa.Builtin, *closure:
		fmt.Fprintf(w, "%p", v) // (an address)

	case rtype:
		io.WriteString(w, v.t.String())

	case tuple:
		// Unreachable in well-formed Go programs
		io.WriteString(w, "(")
		for i, e := range v {
			if i > 0 {
				io.WriteString(w, ", ")
			}
			toWriter(w, e)
		}
		io.WriteString(w, ")")

	default:
		fmt.Fprintf(w, "<%T>", v)
	}
}

// Implements printing of Go values in the style of built-in println.
func toString(v value) string {
	var b bytes.Buffer
	toWriter(&b, v)
	return b.String()
}

// ------------------------------------------------------------------------
// Iterators

type stringIter struct {
	*strings.Reader
	i int
}

func (it *stringIter) next() tuple {
	okv := make(tuple, 3)
	ch, n, err := it.ReadRune()
	ok := err != io.EOF
	okv[0] = ok
	if ok {
		okv[1] = it.i
		okv[2] = ch
	}
	it.i += n
	return okv
}

type mapIter chan [2]value

func (it mapIter) next() tuple {
	kv, ok := <-it
	return tuple{ok, kv[0], kv[1]}
}
<|endoftext|>