<commit_before>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package main

import (
	"fmt"

	"github.com/go-vgo/robotgo"
	// "go-vgo/robotgo"
)

func add() {
	fmt.Println("--- Please press v---")
	eve := robotgo.AddEvent("v")

	if eve {
		fmt.Println("--- You press v---", "v")
	}

	fmt.Println("--- Please press k---")
	keve := robotgo.AddEvent("k")
	if keve {
		fmt.Println("--- You press k---", "k")
	}

	fmt.Println("--- Please press f1---")
	feve := robotgo.AddEvent("f1")
	if feve {
		fmt.Println("You press...", "f1")
	}
}

func event() {
	////////////////////////////////////////////////////////////////////////////////
	// Global event listener
	////////////////////////////////////////////////////////////////////////////////

	add()

	fmt.Println("--- Please press left mouse button---")
	mleft := robotgo.AddEvent("mleft")
	if mleft {
		fmt.Println("--- You press left mouse button---", "mleft")
	}

	mright := robotgo.AddEvent("mright")
	if mright {
		fmt.Println("--- You press right mouse button---", "mright")
	}

	// stop AddEvent
	// robotgo.StopEvent()
}

func main() {
	event()
}
<commit_msg>add more add event examples<commit_after>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package main

import (
	"fmt"

	"github.com/go-vgo/robotgo"
	// "go-vgo/robotgo"
)

func addEvent() {
	ok := robotgo.AddEvents("q", "ctrl", "shift")
	if ok {
		fmt.Println("add events...")
	}

	ok = robotgo.AddEvents("w")
	if ok {
		fmt.Println("add events")
	}

	s := robotgo.Start()
	defer robotgo.End()

	for ev := range s {
		fmt.Println(ev)
	}
}

func add() {
	fmt.Println("--- Please press v---")
	eve := robotgo.AddEvent("v")

	if eve {
		fmt.Println("--- You press v---", "v")
	}

	fmt.Println("--- Please press k---")
	keve := robotgo.AddEvent("k")
	if keve {
		fmt.Println("--- You press k---", "k")
	}

	fmt.Println("--- Please press f1---")
	feve := robotgo.AddEvent("f1")
	if feve {
		fmt.Println("You press...", "f1")
	}
}

func event() {
	////////////////////////////////////////////////////////////////////////////////
	// Global event listener
	////////////////////////////////////////////////////////////////////////////////

	add()

	fmt.Println("--- Please press left mouse button---")
	mleft := robotgo.AddEvent("mleft")
	if mleft {
		fmt.Println("--- You press left mouse button---", "mleft")
	}

	mright := robotgo.AddEvent("mright")
	if mright {
		fmt.Println("--- You press right mouse button---", "mright")
	}

	// stop AddEvent
	// robotgo.StopEvent()
}

func main() {
	addEvent()

	event()
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// ShimType describes a shim type.
type ShimType string

const (
	// CCShimType is the ccShim.
	CCShimType ShimType = "ccShim"

	// NoopShimType is the noopShim.
	NoopShimType ShimType = "noopShim"

	// KataShimType is the Kata Containers shim type.
	KataShimType ShimType = "kataShim"
)

var waitForShimTimeout = 10.0
var consoleFileMode = os.FileMode(0660)

// ShimParams is the structure providing specific parameters needed
// for the execution of the shim binary.
type ShimParams struct {
	Container string
	Token     string
	URL       string
	Console   string
	Terminal  bool
	Detach    bool
	PID       int
}

// ShimConfig is the structure providing specific configuration
// for shim implementations.
type ShimConfig struct {
	Path  string
	Debug bool
}

// Set sets a shim type based on the input string.
func (pType *ShimType) Set(value string) error {
	switch value {
	case "noopShim":
		*pType = NoopShimType
		return nil
	case "ccShim":
		*pType = CCShimType
		return nil
	case "kataShim":
		*pType = KataShimType
		return nil
	default:
		return fmt.Errorf("Unknown shim type %s", value)
	}
}

// String converts a shim type to a string.
func (pType *ShimType) String() string {
	switch *pType {
	case NoopShimType:
		return string(NoopShimType)
	case CCShimType:
		return string(CCShimType)
	case KataShimType:
		return string(KataShimType)
	default:
		return ""
	}
}

// newShim returns a shim from a shim type.
func newShim(pType ShimType) (shim, error) {
	switch pType {
	case NoopShimType:
		return &noopShim{}, nil
	case CCShimType:
		return &ccShim{}, nil
	case KataShimType:
		return &kataShim{}, nil
	default:
		return &noopShim{}, nil
	}
}

// newShimConfig returns a shim config from a generic PodConfig interface.
func newShimConfig(config PodConfig) interface{} {
	switch config.ShimType {
	case NoopShimType:
		return nil
	case CCShimType, KataShimType:
		var shimConfig ShimConfig
		err := mapstructure.Decode(config.ShimConfig, &shimConfig)
		if err != nil {
			return err
		}
		return shimConfig
	default:
		return nil
	}
}

func shimLogger() *logrus.Entry {
	return virtLog.WithField("subsystem", "shim")
}

func signalShim(pid int, sig syscall.Signal) error {
	if pid <= 0 {
		return nil
	}

	shimLogger().WithFields(
		logrus.Fields{
			"shim-pid":    pid,
			"shim-signal": sig,
		}).Info("Signalling shim")

	return syscall.Kill(pid, sig)
}

func stopShim(pid int) error {
	if err := signalShim(pid, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
		return err
	}

	return nil
}

func prepareAndStartShim(pod *Pod, shim shim, cid, token, url string, cmd Cmd) (*Process, error) {
	process := &Process{
		Token:     token,
		StartTime: time.Now().UTC(),
	}

	shimParams := ShimParams{
		Container: cid,
		Token:     token,
		URL:       url,
		Console:   cmd.Console,
		Terminal:  cmd.Interactive,
		Detach:    cmd.Detach,
	}

	var pid int
	if err := pod.network.run(pod.networkNS.NetNsPath, func() (shimErr error) {
		pid, shimErr = shim.start(*pod, shimParams)
		return
	}); err != nil {
		return nil, err
	}

	process.Pid = pid

	return process, nil
}

func startShim(args []string, params ShimParams) (int, error) {
	cmd := exec.Command(args[0], args[1:]...)

	if !params.Detach {
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}

	var f *os.File
	var err error
	if params.Console != "" {
		f, err = os.OpenFile(params.Console, os.O_RDWR, consoleFileMode)
		if err != nil {
			return -1, err
		}

		cmd.Stdin = f
		cmd.Stdout = f
		cmd.Stderr = f
		cmd.SysProcAttr = &syscall.SysProcAttr{
			// Create Session
			Setsid: true,

			// Set Controlling terminal to Ctty
			Setctty: true,
			Ctty:    int(f.Fd()),
		}

	}
	defer func() {
		if f != nil {
			f.Close()
		}
	}()

	if err := cmd.Start(); err != nil {
		return -1, err
	}

	return cmd.Process.Pid, nil
}

func isShimRunning(pid int) (bool, error) {
	process, err := os.FindProcess(pid)
	if err != nil {
		return false, err
	}

	if err := process.Signal(syscall.Signal(0)); err != nil {
		return false, nil
	}

	return true, nil
}

// waitForShim waits for the end of the shim unless it reaches the timeout
// first, returning an error in that case.
func waitForShim(pid int) error {
	if pid <= 0 {
		return nil
	}

	tInit := time.Now()
	for {
		running, err := isShimRunning(pid)
		if err != nil {
			return err
		}

		if !running {
			break
		}

		if time.Since(tInit).Seconds() >= waitForShimTimeout {
			return fmt.Errorf("Shim still running, timeout %f s has been reached", waitForShimTimeout)
		}

		// Let's avoid to run a too busy loop
		time.Sleep(time.Duration(100) * time.Millisecond)
	}

	return nil
}

// shim is the virtcontainers shim interface.
type shim interface {
	// start starts the shim relying on its configuration and on
	// parameters provided.
	start(pod Pod, params ShimParams) (int, error)
}
<commit_msg>shim: Add the ability to spawn the shim in new namespaces<commit_after>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"

	ns "github.com/containers/virtcontainers/pkg/nsenter"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// ShimType describes a shim type.
type ShimType string

const (
	// CCShimType is the ccShim.
	CCShimType ShimType = "ccShim"

	// NoopShimType is the noopShim.
	NoopShimType ShimType = "noopShim"

	// KataShimType is the Kata Containers shim type.
	KataShimType ShimType = "kataShim"
)

var waitForShimTimeout = 10.0
var consoleFileMode = os.FileMode(0660)

// ShimParams is the structure providing specific parameters needed
// for the execution of the shim binary.
type ShimParams struct {
	Container string
	Token     string
	URL       string
	Console   string
	Terminal  bool
	Detach    bool
	PID       int
	CreateNS  []ns.NSType
}

// ShimConfig is the structure providing specific configuration
// for shim implementations.
type ShimConfig struct {
	Path  string
	Debug bool
}

// Set sets a shim type based on the input string.
func (pType *ShimType) Set(value string) error {
	switch value {
	case "noopShim":
		*pType = NoopShimType
		return nil
	case "ccShim":
		*pType = CCShimType
		return nil
	case "kataShim":
		*pType = KataShimType
		return nil
	default:
		return fmt.Errorf("Unknown shim type %s", value)
	}
}

// String converts a shim type to a string.
func (pType *ShimType) String() string {
	switch *pType {
	case NoopShimType:
		return string(NoopShimType)
	case CCShimType:
		return string(CCShimType)
	case KataShimType:
		return string(KataShimType)
	default:
		return ""
	}
}

// newShim returns a shim from a shim type.
func newShim(pType ShimType) (shim, error) {
	switch pType {
	case NoopShimType:
		return &noopShim{}, nil
	case CCShimType:
		return &ccShim{}, nil
	case KataShimType:
		return &kataShim{}, nil
	default:
		return &noopShim{}, nil
	}
}

// newShimConfig returns a shim config from a generic PodConfig interface.
func newShimConfig(config PodConfig) interface{} {
	switch config.ShimType {
	case NoopShimType:
		return nil
	case CCShimType, KataShimType:
		var shimConfig ShimConfig
		err := mapstructure.Decode(config.ShimConfig, &shimConfig)
		if err != nil {
			return err
		}
		return shimConfig
	default:
		return nil
	}
}

func shimLogger() *logrus.Entry {
	return virtLog.WithField("subsystem", "shim")
}

func signalShim(pid int, sig syscall.Signal) error {
	if pid <= 0 {
		return nil
	}

	shimLogger().WithFields(
		logrus.Fields{
			"shim-pid":    pid,
			"shim-signal": sig,
		}).Info("Signalling shim")

	return syscall.Kill(pid, sig)
}

func stopShim(pid int) error {
	if err := signalShim(pid, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
		return err
	}

	return nil
}

func prepareAndStartShim(pod *Pod, shim shim, cid, token, url string, cmd Cmd) (*Process, error) {
	process := &Process{
		Token:     token,
		StartTime: time.Now().UTC(),
	}

	shimParams := ShimParams{
		Container: cid,
		Token:     token,
		URL:       url,
		Console:   cmd.Console,
		Terminal:  cmd.Interactive,
		Detach:    cmd.Detach,
	}

	var pid int
	if err := pod.network.run(pod.networkNS.NetNsPath, func() (shimErr error) {
		pid, shimErr = shim.start(*pod, shimParams)
		return
	}); err != nil {
		return nil, err
	}

	process.Pid = pid

	return process, nil
}

func startShim(args []string, params ShimParams) (int, error) {
	cmd := exec.Command(args[0], args[1:]...)

	if !params.Detach {
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}

	cloneFlags := 0
	for _, nsType := range params.CreateNS {
		cloneFlags |= ns.CloneFlagsTable[nsType]
	}

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: uintptr(cloneFlags),
	}

	var f *os.File
	var err error
	if params.Console != "" {
		f, err = os.OpenFile(params.Console, os.O_RDWR, consoleFileMode)
		if err != nil {
			return -1, err
		}

		cmd.Stdin = f
		cmd.Stdout = f
		cmd.Stderr = f
		// Create Session
		cmd.SysProcAttr.Setsid = true
		// Set Controlling terminal to Ctty
		cmd.SysProcAttr.Setctty = true
		cmd.SysProcAttr.Ctty = int(f.Fd())
	}
	defer func() {
		if f != nil {
			f.Close()
		}
	}()

	if err := cmd.Start(); err != nil {
		return -1, err
	}

	return cmd.Process.Pid, nil
}

func isShimRunning(pid int) (bool, error) {
	process, err := os.FindProcess(pid)
	if err != nil {
		return false, err
	}

	if err := process.Signal(syscall.Signal(0)); err != nil {
		return false, nil
	}

	return true, nil
}

// waitForShim waits for the end of the shim unless it reaches the timeout
// first, returning an error in that case.
func waitForShim(pid int) error {
	if pid <= 0 {
		return nil
	}

	tInit := time.Now()
	for {
		running, err := isShimRunning(pid)
		if err != nil {
			return err
		}

		if !running {
			break
		}

		if time.Since(tInit).Seconds() >= waitForShimTimeout {
			return fmt.Errorf("Shim still running, timeout %f s has been reached", waitForShimTimeout)
		}

		// Let's avoid to run a too busy loop
		time.Sleep(time.Duration(100) * time.Millisecond)
	}

	return nil
}

// shim is the virtcontainers shim interface.
type shim interface {
	// start starts the shim relying on its configuration and on
	// parameters provided.
	start(pod Pod, params ShimParams) (int, error)
}
<|endoftext|>


<commit_before>package httplog

import (
	"encoding/json"
	"net/http"
)

func (httpLogger *internalHttpLogger) jsonHttpResponse(w http.ResponseWriter, httpStatusCode int, httpStatusName string, cascade ...interface{}) {

	// Specify the Content-Type of the HTTP response.
	w.Header().Set("Content-Type", "application/json")

	// Set the logs, which this HttpLogger received, as "X-Log" headers in
	// the HTTP response.
	httpLogger.setLogsInHttpHeaders(w)

	// Write the HTTP headers in the response, with the specified HTTP response code.
	w.WriteHeader(httpStatusCode)

	// Deal with datum.
	datum := make(map[string]interface{})

	for _,x := range cascade {
		switch xx := x.(type) {
		case map[string]interface{}:
			for key, value := range xx {
				datum[key] = value
			}
		case map[string]string:
			for key, value := range xx {
				datum[key] = value
			}
		case string:
			datum["text"] = xx
		}
	}

	datum["status_code"] = httpStatusCode
	datum["status_name"] = httpStatusName

	// Write out the JSON response.
	jsonEncoder := json.NewEncoder(w)
	if nil == jsonEncoder {
		return
	}

	if err := jsonEncoder.Encode(datum); nil != err {
		return
	}
}
<commit_msg>added support for int key/value maps when writing http response body<commit_after>package httplog

import (
	"encoding/json"
	"net/http"
)

func (httpLogger *internalHttpLogger) jsonHttpResponse(w http.ResponseWriter, httpStatusCode int, httpStatusName string, cascade ...interface{}) {

	// Specify the Content-Type of the HTTP response.
	w.Header().Set("Content-Type", "application/json")

	// Set the logs, which this HttpLogger received, as "X-Log" headers in
	// the HTTP response.
	httpLogger.setLogsInHttpHeaders(w)

	// Write the HTTP headers in the response, with the specified HTTP response code.
	w.WriteHeader(httpStatusCode)

	// Deal with datum.
	datum := make(map[string]interface{})

	for _,x := range cascade {
		switch xx := x.(type) {
		case map[string]interface{}:
			for key, value := range xx {
				datum[key] = value
			}
		case map[string]string:
			for key, value := range xx {
				datum[key] = value
			}
		case map[string]int:
			for key, value := range xx {
				datum[key] = value
			}
		case string:
			datum["text"] = xx
		}
	}

	datum["status_code"] = httpStatusCode
	datum["status_name"] = httpStatusName

	// Write out the JSON response.
	jsonEncoder := json.NewEncoder(w)
	if nil == jsonEncoder {
		return
	}

	if err := jsonEncoder.Encode(datum); nil != err {
		return
	}
}
<|endoftext|>


<commit_before>package feeds

import (
	"encoding/json"
	"strings"
	"time"
)

const jsonFeedVersion = "https://jsonfeed.org/version/1"

// JSONAuthor represents the author of the feed or of an individual item
// in the feed
type JSONAuthor struct {
	Name   string `json:"name,omitempty"`
	Url    string `json:"url,omitempty"`
	Avatar string `json:"avatar,omitempty"`
}

// JSONAttachment represents a related resource. Podcasts, for instance, would
// include an attachment that’s an audio or video file.
type JSONAttachment struct {
	Url      string        `json:"url,omitempty"`
	MIMEType string        `json:"mime_type,omitempty"`
	Title    string        `json:"title,omitempty"`
	Size     int32         `json:"size,omitempty"`
	Duration time.Duration `json:"duration_in_seconds,omitempty"`
}

// MarshalJSON implements the json.Marshaler interface.
// The Duration field is marshaled in seconds, all other fields are marshaled
// based upon the definitions in struct tags.
func (a *JSONAttachment) MarshalJSON() ([]byte, error) {
	type EmbeddedJSONAttachment JSONAttachment
	return json.Marshal(&struct {
		Duration float64 `json:"duration_in_seconds,omitempty"`
		*EmbeddedJSONAttachment
	}{
		EmbeddedJSONAttachment: (*EmbeddedJSONAttachment)(a),
		Duration:               a.Duration.Seconds(),
	})
}

// UnmarshalJSON implements the json.Unmarshaler interface.
// The Duration field is expected to be in seconds, all other field types
// match the struct definition.
func (a *JSONAttachment) UnmarshalJSON(data []byte) error {
	type EmbeddedJSONAttachment JSONAttachment
	var raw struct {
		Duration float64 `json:"duration_in_seconds,omitempty"`
		*EmbeddedJSONAttachment
	}
	raw.EmbeddedJSONAttachment = (*EmbeddedJSONAttachment)(a)

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

	if raw.Duration > 0 {
		nsec := int64(raw.Duration * float64(time.Second))
		raw.EmbeddedJSONAttachment.Duration = time.Duration(nsec)
	}

	return nil
}

// JSONItem represents a single entry/post for the feed.
type JSONItem struct {
	Id            string           `json:"id"`
	Url           string           `json:"url,omitempty"`
	ExternalUrl   string           `json:"external_url,omitempty"`
	Title         string           `json:"title,omitempty"`
	ContentHTML   string           `json:"content_html,omitempty"`
	ContentText   string           `json:"content_text,omitempty"`
	Summary       string           `json:"summary,omitempty"`
	Image         string           `json:"image,omitempty"`
	BannerImage   string           `json:"banner_,omitempty"`
	PublishedDate *time.Time       `json:"date_published,omitempty"`
	ModifiedDate  *time.Time       `json:"date_modified,omitempty"`
	Author        *JSONAuthor      `json:"author,omitempty"`
	Tags          []string         `json:"tags,omitempty"`
	Attachments   []JSONAttachment `json:"attachments,omitempty"`
}

// JSONHub describes an endpoint that can be used to subscribe to real-time
// notifications from the publisher of this feed.
type JSONHub struct {
	Type string `json:"type"`
	Url  string `json:"url"`
}

// JSONFeed represents a syndication feed in the JSON Feed Version 1 format.
// Matching the specification found here: https://jsonfeed.org/version/1.
type JSONFeed struct {
	Version     string      `json:"version"`
	Title       string      `json:"title"`
	HomePageUrl string      `json:"home_page_url,omitempty"`
	FeedUrl     string      `json:"feed_url,omitempty"`
	Description string      `json:"description,omitempty"`
	UserComment string      `json:"user_comment,omitempty"`
	NextUrl     string      `json:"next_url,omitempty"`
	Icon        string      `json:"icon,omitempty"`
	Favicon     string      `json:"favicon,omitempty"`
	Author      *JSONAuthor `json:"author,omitempty"`
	Expired     *bool       `json:"expired,omitempty"`
	Hubs        []*JSONItem `json:"hubs,omitempty"`
	Items       []*JSONItem `json:"items,omitempty"`
}

// JSON is used to convert a generic Feed to a JSONFeed.
type JSON struct {
	*Feed
}

// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
func (f *JSON) ToJSON() (string, error) {
	return f.JSONFeed().ToJSON()
}

// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
func (f *JSONFeed) ToJSON() (string, error) {
	data, err := json.MarshalIndent(f, "", "  ")
	if err != nil {
		return "", err
	}

	return string(data), nil
}

// JSONFeed creates a new JSONFeed with a generic Feed struct's data.
func (f *JSON) JSONFeed() *JSONFeed {
	feed := &JSONFeed{
		Version:     jsonFeedVersion,
		Title:       f.Title,
		Description: f.Description,
	}

	if f.Link != nil {
		feed.HomePageUrl = f.Link.Href
	}
	if f.Author != nil {
		feed.Author = &JSONAuthor{
			Name: f.Author.Name,
		}
	}
	for _, e := range f.Items {
		feed.Items = append(feed.Items, newJSONItem(e))
	}
	return feed
}

func newJSONItem(i *Item) *JSONItem {
	item := &JSONItem{
		Id:      i.Id,
		Title:   i.Title,
		Summary: i.Description,
	}

	if i.Link != nil {
		item.Url = i.Link.Href
	}
	if i.Source != nil {
		item.ExternalUrl = i.Source.Href
	}
	if i.Author != nil {
		item.Author = &JSONAuthor{
			Name: i.Author.Name,
		}
	}
	if !i.Created.IsZero() {
		item.PublishedDate = &i.Created
	}
	if !i.Updated.IsZero() {
		item.ModifiedDate = &i.Created
	}
	if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "image/") {
		item.Image = i.Enclosure.Url
	}

	return item
}
<commit_msg>Use item content as JSON content_html<commit_after>package feeds

import (
	"encoding/json"
	"strings"
	"time"
)

const jsonFeedVersion = "https://jsonfeed.org/version/1"

// JSONAuthor represents the author of the feed or of an individual item
// in the feed
type JSONAuthor struct {
	Name   string `json:"name,omitempty"`
	Url    string `json:"url,omitempty"`
	Avatar string `json:"avatar,omitempty"`
}

// JSONAttachment represents a related resource. Podcasts, for instance, would
// include an attachment that’s an audio or video file.
type JSONAttachment struct {
	Url      string        `json:"url,omitempty"`
	MIMEType string        `json:"mime_type,omitempty"`
	Title    string        `json:"title,omitempty"`
	Size     int32         `json:"size,omitempty"`
	Duration time.Duration `json:"duration_in_seconds,omitempty"`
}

// MarshalJSON implements the json.Marshaler interface.
// The Duration field is marshaled in seconds, all other fields are marshaled
// based upon the definitions in struct tags.
func (a *JSONAttachment) MarshalJSON() ([]byte, error) {
	type EmbeddedJSONAttachment JSONAttachment
	return json.Marshal(&struct {
		Duration float64 `json:"duration_in_seconds,omitempty"`
		*EmbeddedJSONAttachment
	}{
		EmbeddedJSONAttachment: (*EmbeddedJSONAttachment)(a),
		Duration:               a.Duration.Seconds(),
	})
}

// UnmarshalJSON implements the json.Unmarshaler interface.
// The Duration field is expected to be in seconds, all other field types
// match the struct definition.
func (a *JSONAttachment) UnmarshalJSON(data []byte) error {
	type EmbeddedJSONAttachment JSONAttachment
	var raw struct {
		Duration float64 `json:"duration_in_seconds,omitempty"`
		*EmbeddedJSONAttachment
	}
	raw.EmbeddedJSONAttachment = (*EmbeddedJSONAttachment)(a)

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

	if raw.Duration > 0 {
		nsec := int64(raw.Duration * float64(time.Second))
		raw.EmbeddedJSONAttachment.Duration = time.Duration(nsec)
	}

	return nil
}

// JSONItem represents a single entry/post for the feed.
type JSONItem struct {
	Id            string           `json:"id"`
	Url           string           `json:"url,omitempty"`
	ExternalUrl   string           `json:"external_url,omitempty"`
	Title         string           `json:"title,omitempty"`
	ContentHTML   string           `json:"content_html,omitempty"`
	ContentText   string           `json:"content_text,omitempty"`
	Summary       string           `json:"summary,omitempty"`
	Image         string           `json:"image,omitempty"`
	BannerImage   string           `json:"banner_,omitempty"`
	PublishedDate *time.Time       `json:"date_published,omitempty"`
	ModifiedDate  *time.Time       `json:"date_modified,omitempty"`
	Author        *JSONAuthor      `json:"author,omitempty"`
	Tags          []string         `json:"tags,omitempty"`
	Attachments   []JSONAttachment `json:"attachments,omitempty"`
}

// JSONHub describes an endpoint that can be used to subscribe to real-time
// notifications from the publisher of this feed.
type JSONHub struct {
	Type string `json:"type"`
	Url  string `json:"url"`
}

// JSONFeed represents a syndication feed in the JSON Feed Version 1 format.
// Matching the specification found here: https://jsonfeed.org/version/1.
type JSONFeed struct {
	Version     string      `json:"version"`
	Title       string      `json:"title"`
	HomePageUrl string      `json:"home_page_url,omitempty"`
	FeedUrl     string      `json:"feed_url,omitempty"`
	Description string      `json:"description,omitempty"`
	UserComment string      `json:"user_comment,omitempty"`
	NextUrl     string      `json:"next_url,omitempty"`
	Icon        string      `json:"icon,omitempty"`
	Favicon     string      `json:"favicon,omitempty"`
	Author      *JSONAuthor `json:"author,omitempty"`
	Expired     *bool       `json:"expired,omitempty"`
	Hubs        []*JSONItem `json:"hubs,omitempty"`
	Items       []*JSONItem `json:"items,omitempty"`
}

// JSON is used to convert a generic Feed to a JSONFeed.
type JSON struct {
	*Feed
}

// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
func (f *JSON) ToJSON() (string, error) {
	return f.JSONFeed().ToJSON()
}

// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
func (f *JSONFeed) ToJSON() (string, error) {
	data, err := json.MarshalIndent(f, "", "  ")
	if err != nil {
		return "", err
	}

	return string(data), nil
}

// JSONFeed creates a new JSONFeed with a generic Feed struct's data.
func (f *JSON) JSONFeed() *JSONFeed {
	feed := &JSONFeed{
		Version:     jsonFeedVersion,
		Title:       f.Title,
		Description: f.Description,
	}

	if f.Link != nil {
		feed.HomePageUrl = f.Link.Href
	}
	if f.Author != nil {
		feed.Author = &JSONAuthor{
			Name: f.Author.Name,
		}
	}
	for _, e := range f.Items {
		feed.Items = append(feed.Items, newJSONItem(e))
	}
	return feed
}

func newJSONItem(i *Item) *JSONItem {
	item := &JSONItem{
		Id:      i.Id,
		Title:   i.Title,
		Summary: i.Description,

		ContentHTML: i.Content,
	}

	if i.Link != nil {
		item.Url = i.Link.Href
	}
	if i.Source != nil {
		item.ExternalUrl = i.Source.Href
	}
	if i.Author != nil {
		item.Author = &JSONAuthor{
			Name: i.Author.Name,
		}
	}
	if !i.Created.IsZero() {
		item.PublishedDate = &i.Created
	}
	if !i.Updated.IsZero() {
		item.ModifiedDate = &i.Created
	}
	if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "image/") {
		item.Image = i.Enclosure.Url
	}

	return item
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"camlistore.org/pkg/jsonsign"
	"camlistore.org/pkg/osutil"
	"camlistore.org/pkg/serverconfig"
	"camlistore.org/pkg/webserver"

	// Storage options:
	_ "camlistore.org/pkg/blobserver/cond"
	_ "camlistore.org/pkg/blobserver/localdisk"
	_ "camlistore.org/pkg/blobserver/remote"
	_ "camlistore.org/pkg/blobserver/replica"
	_ "camlistore.org/pkg/blobserver/s3"
	_ "camlistore.org/pkg/blobserver/shard"
	// Indexers: (also present themselves as storage targets)
	_ "camlistore.org/pkg/index" // base indexer + in-memory dev index
	_ "camlistore.org/pkg/index/mongo"
	_ "camlistore.org/pkg/index/mysql"

	// Handlers:
	_ "camlistore.org/pkg/search"
	_ "camlistore.org/pkg/server" // UI, publish, etc

	"camlistore.org/third_party/code.google.com/p/go.crypto/openpgp"
)

const (
	defCert = "config/selfgen_cert.pem"
	defKey  = "config/selfgen_key.pem"
)

var (
	flagConfigFile = flag.String("configfile", "",
		"Config file to use, relative to the Camlistore configuration directory root. If blank, the default is used or auto-generated.")
)

func exitf(pattern string, args ...interface{}) {
	if !strings.HasSuffix(pattern, "\n") {
		pattern = pattern + "\n"
	}
	fmt.Fprintf(os.Stderr, pattern, args...)
	os.Exit(1)
}

// Mostly copied from $GOROOT/src/pkg/crypto/tls/generate_cert.go
func genSelfTLS(listen string) error {
	priv, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		return fmt.Errorf("failed to generate private key: %s", err)
	}

	now := time.Now()

	hostname, _, err := net.SplitHostPort(listen)
	if err != nil {
		return fmt.Errorf("splitting listen failed: %q", err)
	}

	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(0),
		Subject: pkix.Name{
			CommonName:   hostname,
			Organization: []string{hostname},
		},
		NotBefore:    now.Add(-5 * time.Minute).UTC(),
		NotAfter:     now.AddDate(1, 0, 0).UTC(),
		SubjectKeyId: []byte{1, 2, 3, 4},
		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return fmt.Errorf("Failed to create certificate: %s", err)
	}

	certOut, err := os.Create(defCert)
	if err != nil {
		return fmt.Errorf("failed to open %s for writing: %s", defCert, err)
	}
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	log.Printf("written %s\n", defCert)

	keyOut, err := os.OpenFile(defKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("failed to open %s for writing:", defKey, err)
	}
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()
	log.Printf("written %s\n", defKey)
	return nil
}

// findConfigFile returns the absolute path of the user's
// config file.
// The provided file may be absolute or relative
// to the user's configuration directory.
// If file is empty, a default high-level config is written
// for the user.
func findConfigFile(file string) (absPath string, err error) {
	switch {
	case file == "":
		absPath = osutil.UserServerConfigPath()
		_, err = os.Stat(absPath)
		if os.IsNotExist(err) {
			err = os.MkdirAll(osutil.CamliConfigDir(), 0700)
			if err != nil {
				return
			}
			log.Printf("Generating template config file %s", absPath)
			err = newDefaultConfigFile(absPath)
		}
		return
	case filepath.IsAbs(file):
		absPath = file
	default:
		absPath = filepath.Join(osutil.CamliConfigDir(), file)
	}
	_, err = os.Stat(absPath)
	return
}

func keyIdFromRing(filename string) (keyId string, err error) {
	f, err := os.Open(filename)
	if err != nil {
		return "", fmt.Errorf("reading identity secret ring file: %v", err)
	}
	defer f.Close()
	el, err := openpgp.ReadKeyRing(f)
	if err != nil {
		return "", fmt.Errorf("reading identity secret ring file %s: %v", filename, err)
	}
	if len(el) != 1 {
		return "", fmt.Errorf("identity secret ring file contained %d identities; expected 1", len(el))
	}
	ent := el[0]
	return ent.PrimaryKey.KeyIdShortString(), nil
}

func generateNewSecRing(filename string) (keyId string, err error) {
	ent, err := jsonsign.NewEntity()
	if err != nil {
		return "", fmt.Errorf("generating new identity: %v", err)
	}
	f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return "", err
	}
	defer f.Close()
	err = jsonsign.WriteKeyRing(f, openpgp.EntityList([]*openpgp.Entity{ent}))
	if err != nil {
		return "", fmt.Errorf("writing new key ring to %s: %v", filename, err)
	}
	return ent.PrimaryKey.KeyIdShortString(), nil
}

func newDefaultConfigFile(path string) error {
	conf :=
		`{
	"listen": "localhost:3179",
	"TLS": false,
	"auth": "userpass:camlistore:pass3179:+localhost",
        "identity": "%KEYID%",
	"identitySecretRing": "%SECRING%",
	"blobPath": "%BLOBPATH%",
	"mysql": "",
	"mongo": "",
	"s3": "",
	"replicateTo": [],
	"publish": {}
}
`
	blobDir := osutil.CamliBlobRoot()
	if err := os.MkdirAll(blobDir, 0700); err != nil {
		return fmt.Errorf("Could not create default blobs directory: %v", err)
	}
	conf = strings.Replace(conf, "%BLOBPATH%", blobDir, 1)

	var keyId string
	secRing := osutil.IdentitySecretRing()
	_, err := os.Stat(secRing)
	switch {
	case err == nil:
		keyId, err = keyIdFromRing(secRing)
		log.Printf("Re-using identity with keyId %q found in file %s", keyId, secRing)
	case os.IsNotExist(err):
		keyId, err = generateNewSecRing(secRing)
		log.Printf("Generated new identity with keyId %q in file %s", keyId, secRing)
	}
	if err != nil {
		return fmt.Errorf("Secret ring: %v", err)
	}

	conf = strings.Replace(conf, "%SECRING%", secRing, 1)
	conf = strings.Replace(conf, "%KEYID%", keyId, 1)
	if err := ioutil.WriteFile(path, []byte(conf), 0600); err != nil {
		return fmt.Errorf("Could not create or write default server config: %v", err)
	}
	return nil
}

func setupTLS(ws *webserver.Server, config *serverconfig.Config, listen string) {
	cert, key := config.OptionalString("TLSCertFile", ""), config.OptionalString("TLSKeyFile", "")
	if !config.OptionalBool("https", true) {
		return
	}
	if (cert != "") != (key != "") {
		exitf("TLSCertFile and TLSKeyFile must both be either present or absent")
	}

	if cert == defCert && key == defKey {
		_, err1 := os.Stat(cert)
		_, err2 := os.Stat(key)
		if err1 != nil || err2 != nil {
			if os.IsNotExist(err1) || os.IsNotExist(err2) {
				if err := genSelfTLS(listen); err != nil {
					exitf("Could not generate self-signed TLS cert: %q", err)
				}
			} else {
				exitf("Could not stat cert or key: %q, %q", err1, err2)
			}
		}
	}
	if cert == "" && key == "" {
		err := genSelfTLS(listen)
		if err != nil {
			exitf("Could not generate self signed creds: %q", err)
		}
		cert = defCert
		key = defKey
	}
	ws.SetTLS(cert, key)
}

func main() {
	flag.Parse()

	fileName, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverconfig.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

	ws := webserver.New()
	baseURL := config.RequiredString("baseURL")
	listen := *(webserver.Listen)
	if listen == "" {
		// if command line was empty, use value in config
		listen = strings.TrimLeft(baseURL, "http://")
		listen = strings.TrimLeft(listen, "https://")
	} else {
		// else command line takes precedence
		scheme := strings.Split(baseURL, "://")[0]
		baseURL = scheme + "://" + listen
	}

	setupTLS(ws, config, listen)

	err = config.InstallHandlers(ws, baseURL, nil)
	if err != nil {
		exitf("Error parsing config: %v", err)
	}

	ws.Listen(listen)

	urlOpened := false
	if config.UIPath != "" {
		uiURL := ws.BaseURL() + config.UIPath
		log.Printf("UI available at %s", uiURL)
		if runtime.GOOS == "windows" {
			// Might be double-clicking an icon with no shell window?
			// Just open the URL for them.
			urlOpened = true
			go osutil.OpenURL(uiURL)
		}
	}
	if *flagConfigFile == "" && !urlOpened {
		go func() {
			err := osutil.OpenURL(baseURL)
			if err != nil {
				log.Printf("Failed to open %s in browser: %v", baseURL, err)
			}
		}()
	}
	ws.Serve()
}
<commit_msg>simplify deref expression<commit_after>/*
Copyright 2011 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"camlistore.org/pkg/jsonsign"
	"camlistore.org/pkg/osutil"
	"camlistore.org/pkg/serverconfig"
	"camlistore.org/pkg/webserver"

	// Storage options:
	_ "camlistore.org/pkg/blobserver/cond"
	_ "camlistore.org/pkg/blobserver/localdisk"
	_ "camlistore.org/pkg/blobserver/remote"
	_ "camlistore.org/pkg/blobserver/replica"
	_ "camlistore.org/pkg/blobserver/s3"
	_ "camlistore.org/pkg/blobserver/shard"
	// Indexers: (also present themselves as storage targets)
	_ "camlistore.org/pkg/index" // base indexer + in-memory dev index
	_ "camlistore.org/pkg/index/mongo"
	_ "camlistore.org/pkg/index/mysql"

	// Handlers:
	_ "camlistore.org/pkg/search"
	_ "camlistore.org/pkg/server" // UI, publish, etc

	"camlistore.org/third_party/code.google.com/p/go.crypto/openpgp"
)

const (
	defCert = "config/selfgen_cert.pem"
	defKey  = "config/selfgen_key.pem"
)

var (
	flagConfigFile = flag.String("configfile", "",
		"Config file to use, relative to the Camlistore configuration directory root. If blank, the default is used or auto-generated.")
)

func exitf(pattern string, args ...interface{}) {
	if !strings.HasSuffix(pattern, "\n") {
		pattern = pattern + "\n"
	}
	fmt.Fprintf(os.Stderr, pattern, args...)
	os.Exit(1)
}

// Mostly copied from $GOROOT/src/pkg/crypto/tls/generate_cert.go
func genSelfTLS(listen string) error {
	priv, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		return fmt.Errorf("failed to generate private key: %s", err)
	}

	now := time.Now()

	hostname, _, err := net.SplitHostPort(listen)
	if err != nil {
		return fmt.Errorf("splitting listen failed: %q", err)
	}

	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(0),
		Subject: pkix.Name{
			CommonName:   hostname,
			Organization: []string{hostname},
		},
		NotBefore:    now.Add(-5 * time.Minute).UTC(),
		NotAfter:     now.AddDate(1, 0, 0).UTC(),
		SubjectKeyId: []byte{1, 2, 3, 4},
		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return fmt.Errorf("Failed to create certificate: %s", err)
	}

	certOut, err := os.Create(defCert)
	if err != nil {
		return fmt.Errorf("failed to open %s for writing: %s", defCert, err)
	}
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	log.Printf("written %s\n", defCert)

	keyOut, err := os.OpenFile(defKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("failed to open %s for writing:", defKey, err)
	}
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()
	log.Printf("written %s\n", defKey)
	return nil
}

// findConfigFile returns the absolute path of the user's
// config file.
// The provided file may be absolute or relative
// to the user's configuration directory.
// If file is empty, a default high-level config is written
// for the user.
func findConfigFile(file string) (absPath string, err error) {
	switch {
	case file == "":
		absPath = osutil.UserServerConfigPath()
		_, err = os.Stat(absPath)
		if os.IsNotExist(err) {
			err = os.MkdirAll(osutil.CamliConfigDir(), 0700)
			if err != nil {
				return
			}
			log.Printf("Generating template config file %s", absPath)
			err = newDefaultConfigFile(absPath)
		}
		return
	case filepath.IsAbs(file):
		absPath = file
	default:
		absPath = filepath.Join(osutil.CamliConfigDir(), file)
	}
	_, err = os.Stat(absPath)
	return
}

func keyIdFromRing(filename string) (keyId string, err error) {
	f, err := os.Open(filename)
	if err != nil {
		return "", fmt.Errorf("reading identity secret ring file: %v", err)
	}
	defer f.Close()
	el, err := openpgp.ReadKeyRing(f)
	if err != nil {
		return "", fmt.Errorf("reading identity secret ring file %s: %v", filename, err)
	}
	if len(el) != 1 {
		return "", fmt.Errorf("identity secret ring file contained %d identities; expected 1", len(el))
	}
	ent := el[0]
	return ent.PrimaryKey.KeyIdShortString(), nil
}

func generateNewSecRing(filename string) (keyId string, err error) {
	ent, err := jsonsign.NewEntity()
	if err != nil {
		return "", fmt.Errorf("generating new identity: %v", err)
	}
	f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return "", err
	}
	defer f.Close()
	err = jsonsign.WriteKeyRing(f, openpgp.EntityList([]*openpgp.Entity{ent}))
	if err != nil {
		return "", fmt.Errorf("writing new key ring to %s: %v", filename, err)
	}
	return ent.PrimaryKey.KeyIdShortString(), nil
}

func newDefaultConfigFile(path string) error {
	conf :=
		`{
	"listen": "localhost:3179",
	"TLS": false,
	"auth": "userpass:camlistore:pass3179:+localhost",
        "identity": "%KEYID%",
	"identitySecretRing": "%SECRING%",
	"blobPath": "%BLOBPATH%",
	"mysql": "",
	"mongo": "",
	"s3": "",
	"replicateTo": [],
	"publish": {}
}
`
	blobDir := osutil.CamliBlobRoot()
	if err := os.MkdirAll(blobDir, 0700); err != nil {
		return fmt.Errorf("Could not create default blobs directory: %v", err)
	}
	conf = strings.Replace(conf, "%BLOBPATH%", blobDir, 1)

	var keyId string
	secRing := osutil.IdentitySecretRing()
	_, err := os.Stat(secRing)
	switch {
	case err == nil:
		keyId, err = keyIdFromRing(secRing)
		log.Printf("Re-using identity with keyId %q found in file %s", keyId, secRing)
	case os.IsNotExist(err):
		keyId, err = generateNewSecRing(secRing)
		log.Printf("Generated new identity with keyId %q in file %s", keyId, secRing)
	}
	if err != nil {
		return fmt.Errorf("Secret ring: %v", err)
	}

	conf = strings.Replace(conf, "%SECRING%", secRing, 1)
	conf = strings.Replace(conf, "%KEYID%", keyId, 1)
	if err := ioutil.WriteFile(path, []byte(conf), 0600); err != nil {
		return fmt.Errorf("Could not create or write default server config: %v", err)
	}
	return nil
}

func setupTLS(ws *webserver.Server, config *serverconfig.Config, listen string) {
	cert, key := config.OptionalString("TLSCertFile", ""), config.OptionalString("TLSKeyFile", "")
	if !config.OptionalBool("https", true) {
		return
	}
	if (cert != "") != (key != "") {
		exitf("TLSCertFile and TLSKeyFile must both be either present or absent")
	}

	if cert == defCert && key == defKey {
		_, err1 := os.Stat(cert)
		_, err2 := os.Stat(key)
		if err1 != nil || err2 != nil {
			if os.IsNotExist(err1) || os.IsNotExist(err2) {
				if err := genSelfTLS(listen); err != nil {
					exitf("Could not generate self-signed TLS cert: %q", err)
				}
			} else {
				exitf("Could not stat cert or key: %q, %q", err1, err2)
			}
		}
	}
	if cert == "" && key == "" {
		err := genSelfTLS(listen)
		if err != nil {
			exitf("Could not generate self signed creds: %q", err)
		}
		cert = defCert
		key = defKey
	}
	ws.SetTLS(cert, key)
}

func main() {
	flag.Parse()

	fileName, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverconfig.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

	ws := webserver.New()
	baseURL := config.RequiredString("baseURL")
	listen := *webserver.Listen
	if listen == "" {
		// if command line was empty, use value in config
		listen = strings.TrimLeft(baseURL, "http://")
		listen = strings.TrimLeft(listen, "https://")
	} else {
		// else command line takes precedence
		scheme := strings.Split(baseURL, "://")[0]
		baseURL = scheme + "://" + listen
	}

	setupTLS(ws, config, listen)

	err = config.InstallHandlers(ws, baseURL, nil)
	if err != nil {
		exitf("Error parsing config: %v", err)
	}

	ws.Listen(listen)

	urlOpened := false
	if config.UIPath != "" {
		uiURL := ws.BaseURL() + config.UIPath
		log.Printf("UI available at %s", uiURL)
		if runtime.GOOS == "windows" {
			// Might be double-clicking an icon with no shell window?
			// Just open the URL for them.
			urlOpened = true
			go osutil.OpenURL(uiURL)
		}
	}
	if *flagConfigFile == "" && !urlOpened {
		go func() {
			err := osutil.OpenURL(baseURL)
			if err != nil {
				log.Printf("Failed to open %s in browser: %v", baseURL, err)
			}
		}()
	}
	ws.Serve()
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 JT Olds
// See LICENSE for copying information

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func createKey(name string) (key *rsa.PrivateKey, err error) {
	log.Printf("no key found at %s/%s.key, generating", *statePath, name)
	key, err = rsa.GenerateKey(rand.Reader, 4096)
	if err != nil {
		return nil, err
	}
	f, err := os.OpenFile(filepath.Join(*statePath, fmt.Sprintf("%s.key", name)),
		os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	err = pem.Encode(f, &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key)})
	if err != nil {
		return nil, err
	}
	return key, nil
}

func loadKey(name string) (*rsa.PrivateKey, error) {
	pem_bytes, err := ioutil.ReadFile(
		filepath.Join(*statePath, fmt.Sprintf("%s.key", name)))
	if err != nil {
		if os.IsNotExist(err) {
			return createKey(name)
		}
		return nil, err
	}
	var pem_block *pem.Block
	for {
		pem_block, pem_bytes = pem.Decode(pem_bytes)
		if pem_block == nil || pem_bytes == nil {
			return nil, fmt.Errorf("no pem data found")
		}
		if pem_block.Type == "PRIVATE KEY" ||
			strings.HasSuffix(pem_block.Type, " PRIVATE KEY") {
			break
		}
	}
	return x509.ParsePKCS1PrivateKey(pem_block.Bytes)
}
<commit_msg>the Letsencrypt library we're using doesn't support 4096bit keys<commit_after>// Copyright (C) 2016 JT Olds
// See LICENSE for copying information

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func createKey(name string) (key *rsa.PrivateKey, err error) {
	log.Printf("no key found at %s/%s.key, generating", *statePath, name)
	key, err = rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	f, err := os.OpenFile(filepath.Join(*statePath, fmt.Sprintf("%s.key", name)),
		os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	err = pem.Encode(f, &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key)})
	if err != nil {
		return nil, err
	}
	return key, nil
}

func loadKey(name string) (*rsa.PrivateKey, error) {
	pem_bytes, err := ioutil.ReadFile(
		filepath.Join(*statePath, fmt.Sprintf("%s.key", name)))
	if err != nil {
		if os.IsNotExist(err) {
			return createKey(name)
		}
		return nil, err
	}
	var pem_block *pem.Block
	for {
		pem_block, pem_bytes = pem.Decode(pem_bytes)
		if pem_block == nil || pem_bytes == nil {
			return nil, fmt.Errorf("no pem data found")
		}
		if pem_block.Type == "PRIVATE KEY" ||
			strings.HasSuffix(pem_block.Type, " PRIVATE KEY") {
			break
		}
	}
	return x509.ParsePKCS1PrivateKey(pem_block.Bytes)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var objKinds = map[string]ast.ObjKind{
	"const": ast.Con,
	"type":  ast.Typ,
	"var":   ast.Var,
	"func":  ast.Fun,
}

var (
	verbose = flag.Bool("v", false, "print warnings for unresolved symbols")
	kinds   = flag.String("k", allKinds(), "kinds of symbol types to include")
	printType = flag.Bool("t", false, "print symbol type")
)

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [flags] pkgpath...\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() < 1 || *kinds == "" {
		flag.Usage()
	}
	pkgs := flag.Args()
	mask, err := parseKindMask(*kinds)
	if err != nil {
		printf("gosym: %v", err)
		flag.Usage()
	}
	initGoPath()

	cache := make(map[string]*ast.Package)
	importer := func(path string) *ast.Package {
		if pkg := cache[path]; pkg != nil {
			return pkg
		}
		pkg := types.DefaultImporter(path)
		cache[path] = pkg
		return pkg
	}

	types.Panic = false
	for _, path := range pkgs {
		if pkg := importer(path); pkg != nil {
			for _, f := range pkg.Files {
				checkExprs(path, f, importer, mask)
			}
		}
	}
}

func parseKindMask(kinds string) (uint, error) {
	mask := uint(0)
	ks := strings.Split(kinds, ",")
	for _, k := range ks {
		c, ok := objKinds[k]
		if ok {
			mask |= 1 << uint(c)
		} else {
			return 0, fmt.Errorf("unknown type kind %q", k)
		}
	}
	return mask, nil
}

func allKinds() string {
	var ks []string
	for k := range objKinds {
		ks = append(ks, k)
	}
	return strings.Join(ks, ",")
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

type astVisitor func(n ast.Node) bool

func (f astVisitor) Visit(n ast.Node) ast.Visitor {
	if f(n) {
		return f
	}
	return nil
}

func checkExprs(importPath string, pkg *ast.File, importer types.Importer, kindMask uint) {
	var visit astVisitor
	stopped := false
	visit = func(n ast.Node) bool {
		if stopped {
			return false
		}
		switch n := n.(type) {
		case *ast.ImportSpec:
			// If the file imports a package to ".", abort
			// because we don't support that (yet).
			if n.Name != nil && n.Name.Name == "." {
				stopped = true
				return false
			}
			return true

		case *ast.FuncDecl:
			// add object for init functions
			if n.Recv == nil && n.Name.Name == "init" {
				n.Name.Obj = ast.NewObj(ast.Fun, "init")
			}
			return true

		case *ast.Ident:
			return false

		case *ast.KeyValueExpr:
			// don't try to resolve the key part of a key-value
			// because it might be a map key which doesn't
			// need resolving, and we can't tell without being
			// complicated with types.
			ast.Walk(visit, n.Value)
			return false

		case *ast.SelectorExpr:
			ast.Walk(visit, n.X)
			printSelector(importPath, n, importer, kindMask)
			return false

		case *ast.File:
			for _, d := range n.Decls {
				ast.Walk(visit, d)
			}
			return false
		}

		return true
	}
	ast.Walk(visit, pkg)
}

func printSelector(importPath string, e *ast.SelectorExpr, importer types.Importer, kindMask uint) {
	_, xt := types.ExprType(e.X, importer)
	if xt.Node == nil {
		if *verbose {
			log.Printf("%v: no type for %s", position(e.Pos()), pretty{e.X})
		}
	}
	obj, t := types.ExprType(e, importer)
	if obj == nil {
		if *verbose {
			log.Printf("%v: no object for %s", position(e.Pos()), pretty{e})
		}
		return
	}

	// Exclude any type kinds not in the user-specified mask.
	if (1<<uint(obj.Kind))&kindMask == 0 {
		return
	}

	var pkgPath, xexpr string
	if xt.Kind == ast.Pkg {
		// TODO make the Node of the package its identifier.
		// and put the package name in xt.Pkg.
		pkgPath = litToString(xt.Node.(*ast.ImportSpec).Path)
		xexpr = ""
	} else {
		pos := position(types.DeclPos(obj))
		if pos.Filename == "" {
			panic("empty file name")
		}
		pkgPath = dirToImportPath(filepath.Dir(pos.Filename))
		xexpr = (pretty{depointer(xt.Node)}).String() + "."
	}
	typeStr := ""
	if *printType {
		typeStr = " " + (pretty{t.Node}).String()
	}
	fmt.Printf("%v: %s %s %s%s %s%s\n", position(e.Pos()), importPath, pkgPath, xexpr, e.Sel.Name, obj.Kind, typeStr)
}

func dirToImportPath(dir string) string {
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	return bpkg.ImportPath
}

func depointer(x ast.Node) ast.Node {
	if x, ok := x.(*ast.StarExpr); ok {
		return x.X
	}
	return x
}

// litToString converts from a string literal to a regular string.
func litToString(lit *ast.BasicLit) (v string) {
	if lit.Kind != token.STRING {
		panic("expected string")
	}
	v, err := strconv.Unquote(string(lit.Value))
	if err != nil {
		panic("cannot unquote")
	}
	return v
}

func position(pos token.Pos) token.Position {
	return types.FileSet.Position(pos)
}

type pretty struct {
	n interface{}
}

func (p pretty) String() string {
	var b bytes.Buffer
	printer.Fprint(&b, types.FileSet, p.n)
	return b.String()
}
<commit_msg>gosym: fixes<commit_after>package main

import (
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var objKinds = map[string]ast.ObjKind{
	"const": ast.Con,
	"type":  ast.Typ,
	"var":   ast.Var,
	"func":  ast.Fun,
}

var (
	verbose   = flag.Bool("v", false, "print warnings for unresolved symbols")
	kinds     = flag.String("k", allKinds(), "kinds of symbol types to include")
	printType = flag.Bool("t", false, "print symbol type")
	internal  = flag.Bool("internal", false, "print internal references too")
)

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [flags] pkgpath...\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() < 1 || *kinds == "" {
		flag.Usage()
	}
	pkgs := flag.Args()
	mask, err := parseKindMask(*kinds)
	if err != nil {
		printf("gosym: %v", err)
		flag.Usage()
	}
	initGoPath()

	cache := make(map[string]*ast.Package)
	importer := func(path string) *ast.Package {
		if pkg := cache[path]; pkg != nil {
			return pkg
		}
		pkg := types.DefaultImporter(path)
		cache[path] = pkg
		return pkg
	}

	types.Panic = false
	for _, path := range pkgs {
		if pkg := importer(path); pkg != nil {
			for _, f := range pkg.Files {
				checkExprs(path, f, importer, mask)
			}
		}
	}
}

func parseKindMask(kinds string) (uint, error) {
	mask := uint(0)
	ks := strings.Split(kinds, ",")
	for _, k := range ks {
		c, ok := objKinds[k]
		if ok {
			mask |= 1 << uint(c)
		} else {
			return 0, fmt.Errorf("unknown type kind %q", k)
		}
	}
	return mask, nil
}

func allKinds() string {
	var ks []string
	for k := range objKinds {
		ks = append(ks, k)
	}
	return strings.Join(ks, ",")
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

type astVisitor func(n ast.Node) bool

func (f astVisitor) Visit(n ast.Node) ast.Visitor {
	if f(n) {
		return f
	}
	return nil
}

func checkExprs(importPath string, pkg *ast.File, importer types.Importer, kindMask uint) {
	var visit astVisitor
	stopped := false
	visit = func(n ast.Node) bool {
		if stopped {
			return false
		}
		switch n := n.(type) {
		case *ast.ImportSpec:
			// If the file imports a package to ".", abort
			// because we don't support that (yet).
			if n.Name != nil && n.Name.Name == "." {
				stopped = true
				return false
			}
			return true

		case *ast.FuncDecl:
			// add object for init functions
			if n.Recv == nil && n.Name.Name == "init" {
				n.Name.Obj = ast.NewObj(ast.Fun, "init")
			}
			return true

		case *ast.Ident:
			return false

		case *ast.KeyValueExpr:
			// don't try to resolve the key part of a key-value
			// because it might be a map key which doesn't
			// need resolving, and we can't tell without being
			// complicated with types.
			ast.Walk(visit, n.Value)
			return false

		case *ast.SelectorExpr:
			ast.Walk(visit, n.X)
			printSelector(importPath, n, importer, kindMask)
			return false

		case *ast.File:
			for _, d := range n.Decls {
				ast.Walk(visit, d)
			}
			return false
		}

		return true
	}
	ast.Walk(visit, pkg)
}

func printSelector(importPath string, e *ast.SelectorExpr, importer types.Importer, kindMask uint) {
	_, xt := types.ExprType(e.X, importer)
	if xt.Node == nil {
		if *verbose {
			log.Printf("%v: no type for %s", position(e.Pos()), pretty{e.X})
		}
	}
	obj, t := types.ExprType(e, importer)
	if obj == nil {
		if *verbose {
			log.Printf("%v: no object for %s", position(e.Pos()), pretty{e})
		}
		return
	}

	// Exclude any type kinds not in the user-specified mask.
	if (1<<uint(obj.Kind))&kindMask == 0 {
		return
	}

	var pkgPath, xexpr string
	if xt.Kind == ast.Pkg {
		// TODO make the Node of the package its identifier.
		// and put the package name in xt.Pkg.
		pkgPath = litToString(xt.Node.(*ast.ImportSpec).Path)
		xexpr = ""
	} else {
		pos := position(types.DeclPos(obj))
		if pos.Filename == "" {
			panic("empty file name")
		}
		pkgPath = dirToImportPath(filepath.Dir(pos.Filename))
		xexpr = (pretty{depointer(xt.Node)}).String() + "."
	}
	if !*internal && pkgPath == importPath {
		return
	}
	typeStr := ""
	if *printType {
		typeStr = " " + (pretty{t.Node}).String()
	}
	fmt.Printf("%v: %s %s %s%s %s%s\n", position(e.Pos()), importPath, pkgPath, xexpr, e.Sel.Name, obj.Kind, typeStr)
}

func dirToImportPath(dir string) string {
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	return bpkg.ImportPath
}

func depointer(x ast.Node) ast.Node {
	if x, ok := x.(*ast.StarExpr); ok {
		return x.X
	}
	return x
}

// litToString converts from a string literal to a regular string.
func litToString(lit *ast.BasicLit) (v string) {
	if lit.Kind != token.STRING {
		panic("expected string")
	}
	v, err := strconv.Unquote(string(lit.Value))
	if err != nil {
		panic("cannot unquote")
	}
	return v
}

func position(pos token.Pos) token.Position {
	return types.FileSet.Position(pos)
}

type pretty struct {
	n interface{}
}

func (p pretty) String() string {
	var b bytes.Buffer
	printer.Fprint(&b, types.FileSet, p.n)
	return b.String()
}
<|endoftext|>


<commit_before>package multiverse

import (
	"strings"
	"unicode"

	"github.com/CasualSuperman/Diorite/trie"
	"github.com/CasualSuperman/levenshtein"
	"github.com/dotCypress/phonetics"
)

func generatePhoneticsMaps(cards []*Card) trie.Trie {
	metaphoneMap := trie.Alt()

	for i, c := range cards {
		name := preventUnicode(c.Name)
		for _, word := range strings.Split(name, " ") {
			if len(word) < 4 {
				continue
			}
			mtp := phonetics.EncodeMetaphone(word)

			others, ok := metaphoneMap.Get(mtp)
			if ok {
				slice := others.([]int)
				slice = append(slice, i)
				metaphoneMap.Remove(mtp)
				metaphoneMap.Add(mtp, slice)
			} else {
				metaphoneMap.Add(mtp, []int{i})
			}
		}
	}

	return metaphoneMap
}

var phoneticsCache = make(map[string]string)

func getMetaphone(s string) string {
	if cached, ok := phoneticsCache[s]; ok {
		return cached
	}

	m := phonetics.EncodeMetaphone(s)
	phoneticsCache[s] = m
	return m
}

var unicodeCache = make(map[string]string)

func preventUnicode(name string) string {
	name = strings.ToLower(name)
	if cached, ok := unicodeCache[name]; ok {
		return cached
	}

	clean := ""
	for _, r := range name {
		if r > 128 {
			switch r {
			case 'á', 'à', 'â':
				clean += "a"
			case 'é':
				clean += "e"
			case 'í':
				clean += "i"
			case 'ö':
				clean += "o"
			case 'û', 'ú':
				clean += "u"

			case 'Æ', 'æ':
				clean += "ae"

			case '®':
				// We know this is an option but we're explicitly ignoring it.

			default:
			}
		} else {
			if r == ' ' || unicode.IsLetter(r) {
				clean += string(r)
			}
		}
	}

	unicodeCache[name] = clean

	return clean
}

type fuzzySearchList []struct {
	index      int
	similarity float32
}

// FuzzyNameSearch searches for a card with a similar name to the searchPhrase, and returns count or less of the most likely results.
func (m Multiverse) FuzzyNameSearch(searchPhrase string, count int) []*Card {
	var aggregator = make(fuzzySearchList, 0, count)
	searchPhrase = preventUnicode(searchPhrase)
	searchGrams2 := newNGram(searchPhrase, 2)
	searchGrams3 := newNGram(searchPhrase, 3)

	for _, searchTerm := range strings.Split(searchPhrase, " ") {
		for _, candidate := range m.Pronunciations.Search(getMetaphone(searchTerm)) {
			cardIndices, _ := m.Pronunciations.Get(candidate)
		cardLoop:
			for _, cardIndex := range cardIndices.([]int) {
				for _, i := range aggregator {
					if i.index == cardIndex {
						continue cardLoop
					}
				}
				name := preventUnicode(m.Cards.List[cardIndex].Name)

				bestMatch := 0
				for _, word := range strings.Split(name, " ") {
					match := phonetics.DifferenceSoundex(word, searchTerm)
					if match > bestMatch {
						bestMatch = match
					}
				}

				similarity := searchGrams2.Similarity(name)
				similarity *= searchGrams3.Similarity(name)
				similarity *= float32(bestMatch)
				similarity /= float32(levenshtein.Distance(searchPhrase, name))
				similarity *= float32(len(name))

				if strings.Contains(name, searchPhrase) {
					similarity *= 10
				}

				var app = struct {
					index      int
					similarity float32
				}{
					cardIndex,
					similarity,
				}

				if len(aggregator) < cap(aggregator) {
					i := len(aggregator)
					aggregator = aggregator[:i+1]
					aggregator[i] = app
				} else {
					for i := count - 1; i >= 0; i-- {
						if aggregator[i].similarity < app.similarity {
							if i < count-1 {
								aggregator[i+1] = aggregator[i]
							}
							aggregator[i] = app
						} else {
							i = 0
						}
					}
				}
			}
		}
	levenshteinLoop:
		for cardIndex, card := range m.Cards.List {
			for _, word := range strings.Split(preventUnicode(card.Name), " ") {
				if levenshtein.Distance(word, searchTerm) <= len(searchTerm)/3 {

					name := preventUnicode(card.Name)
					similarity := searchGrams2.Similarity(name)
					similarity *= searchGrams3.Similarity(name)
					similarity *= float32(phonetics.DifferenceSoundex(word, searchTerm)) / 10.0
					similarity /= float32(levenshtein.Distance(searchPhrase, name))
					similarity *= float32(len(name))
					var app = struct {
						index      int
						similarity float32
					}{
						cardIndex,
						similarity,
					}

					for i, ci := range aggregator {
						if cardIndex == ci.index {
							if ci.similarity < similarity {
								aggregator[i] = app
							}
							continue levenshteinLoop
						}
					}

					if len(aggregator) < cap(aggregator) {
						i := len(aggregator)
						aggregator = aggregator[:i+1]
						aggregator[i] = app
					} else {
						for i := count - 1; i >= 0; i-- {
							if aggregator[i].similarity < app.similarity {
								if i < count-1 {
									aggregator[i+1] = aggregator[i]
								}
								aggregator[i] = app
							} else {
								i = 0
							}
						}
					}
				}
			}
		}
	}

	if len(aggregator) < count {
		count = len(aggregator)
	}

	results := make([]*Card, count)

	for i, card := range aggregator {
		results[i] = m.Cards.List[card.index]
	}

	return results
}
<commit_msg>Integer math is faster.<commit_after>package multiverse

import (
	"strings"
	"unicode"

	"github.com/CasualSuperman/Diorite/trie"
	"github.com/CasualSuperman/levenshtein"
	"github.com/dotCypress/phonetics"
)

func generatePhoneticsMaps(cards []*Card) trie.Trie {
	metaphoneMap := trie.Alt()

	for i, c := range cards {
		name := preventUnicode(c.Name)
		for _, word := range strings.Split(name, " ") {
			if len(word) < 4 {
				continue
			}
			mtp := phonetics.EncodeMetaphone(word)

			others, ok := metaphoneMap.Get(mtp)
			if ok {
				slice := others.([]int)
				slice = append(slice, i)
				metaphoneMap.Remove(mtp)
				metaphoneMap.Add(mtp, slice)
			} else {
				metaphoneMap.Add(mtp, []int{i})
			}
		}
	}

	return metaphoneMap
}

var phoneticsCache = make(map[string]string)

func getMetaphone(s string) string {
	if cached, ok := phoneticsCache[s]; ok {
		return cached
	}

	m := phonetics.EncodeMetaphone(s)
	phoneticsCache[s] = m
	return m
}

var unicodeCache = make(map[string]string)

func preventUnicode(name string) string {
	name = strings.ToLower(name)
	if cached, ok := unicodeCache[name]; ok {
		return cached
	}

	clean := ""
	for _, r := range name {
		if r > 128 {
			switch r {
			case 'á', 'à', 'â':
				clean += "a"
			case 'é':
				clean += "e"
			case 'í':
				clean += "i"
			case 'ö':
				clean += "o"
			case 'û', 'ú':
				clean += "u"

			case 'Æ', 'æ':
				clean += "ae"

			case '®':
				// We know this is an option but we're explicitly ignoring it.

			default:
			}
		} else {
			if r == ' ' || unicode.IsLetter(r) {
				clean += string(r)
			}
		}
	}

	unicodeCache[name] = clean

	return clean
}

type fuzzySearchList []struct {
	index      int
	similarity float32
}

// FuzzyNameSearch searches for a card with a similar name to the searchPhrase, and returns count or less of the most likely results.
func (m Multiverse) FuzzyNameSearch(searchPhrase string, count int) []*Card {
	var aggregator = make(fuzzySearchList, 0, count)
	searchPhrase = preventUnicode(searchPhrase)
	searchGrams2 := newNGram(searchPhrase, 2)
	searchGrams3 := newNGram(searchPhrase, 3)

	for _, searchTerm := range strings.Split(searchPhrase, " ") {
		for _, candidate := range m.Pronunciations.Search(getMetaphone(searchTerm)) {
			cardIndices, _ := m.Pronunciations.Get(candidate)
		cardLoop:
			for _, cardIndex := range cardIndices.([]int) {
				for _, i := range aggregator {
					if i.index == cardIndex {
						continue cardLoop
					}
				}
				name := preventUnicode(m.Cards.List[cardIndex].Name)

				bestMatch := 0
				for _, word := range strings.Split(name, " ") {
					match := phonetics.DifferenceSoundex(word, searchTerm)
					if match > bestMatch {
						bestMatch = match
					}
				}

				similarity := searchGrams2.Similarity(name)
				similarity *= searchGrams3.Similarity(name)
				similarity *= float32(len(name) * bestMatch)
				similarity /= float32(levenshtein.Distance(searchPhrase, name))

				if strings.Contains(name, searchPhrase) {
					similarity *= 10
				}

				var app = struct {
					index      int
					similarity float32
				}{
					cardIndex,
					similarity,
				}

				if len(aggregator) < cap(aggregator) {
					i := len(aggregator)
					aggregator = aggregator[:i+1]
					aggregator[i] = app
				} else {
					for i := count - 1; i >= 0; i-- {
						if aggregator[i].similarity < app.similarity {
							if i < count-1 {
								aggregator[i+1] = aggregator[i]
							}
							aggregator[i] = app
						} else {
							i = 0
						}
					}
				}
			}
		}
	levenshteinLoop:
		for cardIndex, card := range m.Cards.List {
			for _, word := range strings.Split(preventUnicode(card.Name), " ") {
				if levenshtein.Distance(word, searchTerm) <= len(searchTerm)/3 {

					name := preventUnicode(card.Name)
					similarity := searchGrams2.Similarity(name)
					similarity *= searchGrams3.Similarity(name)
					similarity *= float32(len(name) * phonetics.DifferenceSoundex(word, searchTerm)) / 10.0
					similarity /= float32(levenshtein.Distance(searchPhrase, name))
					var app = struct {
						index      int
						similarity float32
					}{
						cardIndex,
						similarity,
					}

					for i, ci := range aggregator {
						if cardIndex == ci.index {
							if ci.similarity < similarity {
								aggregator[i] = app
							}
							continue levenshteinLoop
						}
					}

					if len(aggregator) < cap(aggregator) {
						i := len(aggregator)
						aggregator = aggregator[:i+1]
						aggregator[i] = app
					} else {
						for i := count - 1; i >= 0; i-- {
							if aggregator[i].similarity < app.similarity {
								if i < count-1 {
									aggregator[i+1] = aggregator[i]
								}
								aggregator[i] = app
							} else {
								i = 0
							}
						}
					}
				}
			}
		}
	}

	if len(aggregator) < count {
		count = len(aggregator)
	}

	results := make([]*Card, count)

	for i, card := range aggregator {
		results[i] = m.Cards.List[card.index]
	}

	return results
}
<|endoftext|>


<commit_before>// Package kite is a library for creating micro-services.  Two main types
// implemented by this package are Kite for creating a micro-service server
// called "Kite" and Client for communicating with another kites.
package kite

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite/config"
	"github.com/koding/kite/protocol"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

var hostname string

func init() {
	var err error
	hostname, err = os.Hostname()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot get hostname: %s", err.Error()))
	}
}

// Kite defines a single process that enables distributed service messaging
// amongst the peers it is connected. A Kite process acts as a Client and as a
// Server. That means it can receive request, process them, but it also can
// make request to other kites.
//
// Do not use this struct directly. Use kite.New function, add your handlers
// with HandleFunc mehtod, then call Run method to start the inbuilt server (or
// pass it to any http.Handler compatible server)
type Kite struct {
	Config *config.Config

	// Log logs with the given Logger interface
	Log Logger

	// SetLogLevel changes the level of the logger. Default is INFO.
	SetLogLevel func(Level)

	// Contains different functions for authenticating user from request.
	// Keys are the authentication types (options.auth.type).
	Authenticators map[string]func(*Request) error

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Handlers added with Kite.HandleFunc().
	handlers     map[string]*Method // method map for exported methods
	preHandlers  []Handler          // a list of handlers that are executed before any handler
	postHandlers []Handler          // a list of handlers that are executed after any handler

	// MethodHandling defines how the kite is returning the response for
	// multiple handlers
	MethodHandling MethodHandling

	// HTTP muxer
	httpHandler *http.ServeMux

	// kontrolclient is used to register to kontrol and query third party kites
	// from kontrol
	kontrol *kontrolClient

	// Handlers to call when a new connection is received.
	onConnectHandlers []func(*Client)

	// Handlers to call before the first request of connected kite.
	onFirstRequestHandlers []func(*Client)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*Client)

	// server fields, are initialized and used when
	// TODO: move them to their own struct, just like KontrolClient
	listener  net.Listener
	TLSConfig *tls.Config
	readyC    chan bool // To signal when kite is ready to accept connections
	closeC    chan bool // To signal when kite is closed with Close()

	name    string
	version string
	Id      string // Unique kite instance id
}

// New creates, initialize and then returns a new Kite instance. Version must
// be in 3-digit semantic form. Name is important that it's also used to be
// searched by others.
func New(name, version string) *Kite {
	if name == "" {
		panic("kite: name cannot be empty")
	}

	if digits := strings.Split(version, "."); len(digits) != 3 {
		panic("kite: version must be 3-digits semantic version")
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot generate unique ID: %s", err.Error()))
	}

	l, setlevel := newLogger(name)

	kClient := &kontrolClient{
		readyConnected:  make(chan struct{}),
		readyRegistered: make(chan struct{}),
		registerChan:    make(chan *url.URL, 1),
	}

	k := &Kite{
		Config:             config.New(),
		Log:                l,
		SetLogLevel:        setlevel,
		Authenticators:     make(map[string]func(*Request) error),
		trustedKontrolKeys: make(map[string]string),
		handlers:           make(map[string]*Method),
		preHandlers:        make([]Handler, 0),
		postHandlers:       make([]Handler, 0),
		kontrol:            kClient,
		name:               name,
		version:            version,
		Id:                 kiteID.String(),
		readyC:             make(chan bool),
		closeC:             make(chan bool),
		httpHandler:        http.NewServeMux(),
	}

	// All websocket communication is done through this endpoint.
	k.HandleHTTP("/", sockjs.NewHandler("/kite", sockjs.DefaultOptions, k.sockjsHandler))

	// Add useful debug logs
	k.OnConnect(func(c *Client) { k.Log.Debug("New session: %s", c.session.ID()) })
	k.OnFirstRequest(func(c *Client) { k.Log.Debug("Session %q is identified as %q", c.session.ID(), c.Kite) })
	k.OnDisconnect(func(c *Client) { k.Log.Debug("Kite has disconnected: %q", c.Kite) })

	// Every kite should be able to authenticate the user from token.
	// Tokens are granted by Kontrol Kite.
	k.Authenticators["token"] = k.AuthenticateFromToken

	// A kite accepts requests with the same username.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register default methods and handlers.
	k.addDefaultHandlers()

	return k
}

// Kite returns the definition of the kite.
func (k *Kite) Kite() *protocol.Kite {
	return &protocol.Kite{
		Username:    k.Config.Username,
		Environment: k.Config.Environment,
		Name:        k.name,
		Version:     k.version,
		Region:      k.Config.Region,
		Hostname:    hostname,
		ID:          k.Id,
	}
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

// HandleHTTP registers the HTTP handler for the given pattern into the
// underlying HTTP muxer.
func (k *Kite) HandleHTTP(pattern string, handler http.Handler) {
	k.httpHandler.Handle(pattern, handler)
}

// HandleHTTPFunc registers the HTTP handler for the given pattern into the
// underlying HTTP muxer.
func (k *Kite) HandleHTTPFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	k.httpHandler.HandleFunc(pattern, handler)
}

// ServeHTTP helps Kite to satisfy the http.Handler interface. So kite can be
// used as a standard http server.
func (k *Kite) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	k.httpHandler.ServeHTTP(w, req)
}

func (k *Kite) sockjsHandler(session sockjs.Session) {
	defer session.Close(0, "")

	// This Client also handles the connected client.
	// Since both sides can send/receive messages the client code is reused here.
	c := k.NewClient("")
	c.session = session

	go c.sendHub()
	c.wg.Add(1) // with sendHub we added a new listener

	k.callOnConnectHandlers(c)

	// Run after methods are registered and delegate is set
	c.readLoop()

	c.callOnDisconnectHandlers()
	k.callOnDisconnectHandlers(c)
}

func (k *Kite) OnConnect(handler func(*Client)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnFirstRequest registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnFirstRequest(handler func(*Client)) {
	k.onFirstRequestHandlers = append(k.onFirstRequestHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*Client)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

func (k *Kite) callOnConnectHandlers(c *Client) {
	for _, handler := range k.onConnectHandlers {
		handler(c)
	}
}

func (k *Kite) callOnFirstRequestHandlers(c *Client) {
	for _, handler := range k.onFirstRequestHandlers {
		handler(c)
	}
}

func (k *Kite) callOnDisconnectHandlers(c *Client) {
	for _, handler := range k.onDisconnectHandlers {
		handler(c)
	}
}

// RSAKey returns the corresponding public key for the issuer of the token.
// It is called by jwt-go package when validating the signature in the token.
func (k *Kite) RSAKey(token *jwt.Token) (interface{}, error) {
	if k.Config.KontrolKey == "" {
		panic("kontrol key is not set in config")
	}

	issuer, ok := token.Claims["iss"].(string)
	if !ok {
		return nil, errors.New("token does not contain a valid issuer claim")
	}

	if issuer != k.Config.KontrolUser {
		return nil, fmt.Errorf("issuer is not trusted: %s", issuer)
	}

	return []byte(k.Config.KontrolKey), nil
}
<commit_msg>kite: fix adding routes of "/" to http muxer<commit_after>// Package kite is a library for creating micro-services.  Two main types
// implemented by this package are Kite for creating a micro-service server
// called "Kite" and Client for communicating with another kites.
package kite

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/mux"
	"github.com/koding/kite/config"
	"github.com/koding/kite/protocol"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

var hostname string

func init() {
	var err error
	hostname, err = os.Hostname()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot get hostname: %s", err.Error()))
	}
}

// Kite defines a single process that enables distributed service messaging
// amongst the peers it is connected. A Kite process acts as a Client and as a
// Server. That means it can receive request, process them, but it also can
// make request to other kites.
//
// Do not use this struct directly. Use kite.New function, add your handlers
// with HandleFunc mehtod, then call Run method to start the inbuilt server (or
// pass it to any http.Handler compatible server)
type Kite struct {
	Config *config.Config

	// Log logs with the given Logger interface
	Log Logger

	// SetLogLevel changes the level of the logger. Default is INFO.
	SetLogLevel func(Level)

	// Contains different functions for authenticating user from request.
	// Keys are the authentication types (options.auth.type).
	Authenticators map[string]func(*Request) error

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Handlers added with Kite.HandleFunc().
	handlers     map[string]*Method // method map for exported methods
	preHandlers  []Handler          // a list of handlers that are executed before any handler
	postHandlers []Handler          // a list of handlers that are executed after any handler

	// MethodHandling defines how the kite is returning the response for
	// multiple handlers
	MethodHandling MethodHandling

	// HTTP muxer
	muxer *mux.Router

	// kontrolclient is used to register to kontrol and query third party kites
	// from kontrol
	kontrol *kontrolClient

	// Handlers to call when a new connection is received.
	onConnectHandlers []func(*Client)

	// Handlers to call before the first request of connected kite.
	onFirstRequestHandlers []func(*Client)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*Client)

	// server fields, are initialized and used when
	// TODO: move them to their own struct, just like KontrolClient
	listener  net.Listener
	TLSConfig *tls.Config
	readyC    chan bool // To signal when kite is ready to accept connections
	closeC    chan bool // To signal when kite is closed with Close()

	name    string
	version string
	Id      string // Unique kite instance id
}

// New creates, initialize and then returns a new Kite instance. Version must
// be in 3-digit semantic form. Name is important that it's also used to be
// searched by others.
func New(name, version string) *Kite {
	if name == "" {
		panic("kite: name cannot be empty")
	}

	if digits := strings.Split(version, "."); len(digits) != 3 {
		panic("kite: version must be 3-digits semantic version")
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot generate unique ID: %s", err.Error()))
	}

	l, setlevel := newLogger(name)

	kClient := &kontrolClient{
		readyConnected:  make(chan struct{}),
		readyRegistered: make(chan struct{}),
		registerChan:    make(chan *url.URL, 1),
	}

	k := &Kite{
		Config:             config.New(),
		Log:                l,
		SetLogLevel:        setlevel,
		Authenticators:     make(map[string]func(*Request) error),
		trustedKontrolKeys: make(map[string]string),
		handlers:           make(map[string]*Method),
		preHandlers:        make([]Handler, 0),
		postHandlers:       make([]Handler, 0),
		kontrol:            kClient,
		name:               name,
		version:            version,
		Id:                 kiteID.String(),
		readyC:             make(chan bool),
		closeC:             make(chan bool),
		muxer:              mux.NewRouter(),
	}

	// All sockjs communication is done through this endpoint..
	k.muxer.PathPrefix("/kite").Handler(sockjs.NewHandler("/kite", sockjsOpts, k.sockjsHandler))

	// Add useful debug logs
	k.OnConnect(func(c *Client) { k.Log.Debug("New session: %s", c.session.ID()) })
	k.OnFirstRequest(func(c *Client) { k.Log.Debug("Session %q is identified as %q", c.session.ID(), c.Kite) })
	k.OnDisconnect(func(c *Client) { k.Log.Debug("Kite has disconnected: %q", c.Kite) })

	// Every kite should be able to authenticate the user from token.
	// Tokens are granted by Kontrol Kite.
	k.Authenticators["token"] = k.AuthenticateFromToken

	// A kite accepts requests with the same username.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register default methods and handlers.
	k.addDefaultHandlers()

	return k
}

// Kite returns the definition of the kite.
func (k *Kite) Kite() *protocol.Kite {
	return &protocol.Kite{
		Username:    k.Config.Username,
		Environment: k.Config.Environment,
		Name:        k.name,
		Version:     k.version,
		Region:      k.Config.Region,
		Hostname:    hostname,
		ID:          k.Id,
	}
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

// HandleHTTP registers the HTTP handler for the given pattern into the
// underlying HTTP muxer.
func (k *Kite) HandleHTTP(pattern string, handler http.Handler) {
	k.muxer.Handle(pattern, handler)
}

// HandleHTTPFunc registers the HTTP handler for the given pattern into the
// underlying HTTP muxer.
func (k *Kite) HandleHTTPFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	k.muxer.HandleFunc(pattern, handler)
}

// ServeHTTP helps Kite to satisfy the http.Handler interface. So kite can be
// used as a standard http server.
func (k *Kite) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	k.muxer.ServeHTTP(w, req)
}

func (k *Kite) sockjsHandler(session sockjs.Session) {
	defer session.Close(0, "")

	// This Client also handles the connected client.
	// Since both sides can send/receive messages the client code is reused here.
	c := k.NewClient("")
	c.session = session

	go c.sendHub()
	c.wg.Add(1) // with sendHub we added a new listener

	k.callOnConnectHandlers(c)

	// Run after methods are registered and delegate is set
	c.readLoop()

	c.callOnDisconnectHandlers()
	k.callOnDisconnectHandlers(c)
}

func (k *Kite) OnConnect(handler func(*Client)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnFirstRequest registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnFirstRequest(handler func(*Client)) {
	k.onFirstRequestHandlers = append(k.onFirstRequestHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*Client)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

func (k *Kite) callOnConnectHandlers(c *Client) {
	for _, handler := range k.onConnectHandlers {
		handler(c)
	}
}

func (k *Kite) callOnFirstRequestHandlers(c *Client) {
	for _, handler := range k.onFirstRequestHandlers {
		handler(c)
	}
}

func (k *Kite) callOnDisconnectHandlers(c *Client) {
	for _, handler := range k.onDisconnectHandlers {
		handler(c)
	}
}

// RSAKey returns the corresponding public key for the issuer of the token.
// It is called by jwt-go package when validating the signature in the token.
func (k *Kite) RSAKey(token *jwt.Token) (interface{}, error) {
	if k.Config.KontrolKey == "" {
		panic("kontrol key is not set in config")
	}

	issuer, ok := token.Claims["iss"].(string)
	if !ok {
		return nil, errors.New("token does not contain a valid issuer claim")
	}

	if issuer != k.Config.KontrolUser {
		return nil, fmt.Errorf("issuer is not trusted: %s", issuer)
	}

	return []byte(k.Config.KontrolKey), nil
}
<|endoftext|>