<commit_before>package rbd_test

import (
    "testing"
    "github.com/noahdesu/go-ceph/rados"
    "github.com/noahdesu/go-ceph/rbd"
    "github.com/stretchr/testify/assert"
    "os/exec"
    "sort"
)

func GetUUID() string {
    out, _ := exec.Command("uuidgen").Output()
    return string(out[:36])
}

func TestVersion(t *testing.T) {
    var major, minor, patch = rbd.Version()
    assert.False(t, major < 0 || major > 1000, "invalid major")
    assert.False(t, minor < 0 || minor > 1000, "invalid minor")
    assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestGetImageNames(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    poolname := GetUUID()
    err := conn.MakePool(poolname)
    assert.NoError(t, err)

    ioctx, err := conn.OpenIOContext(poolname)
    assert.NoError(t, err)

    createdList := []string{}
    for i := 0; i < 10; i++ {
        name := GetUUID()
        err = rbd.Create(ioctx, name, 1<<22)
        assert.NoError(t, err)
        createdList = append(createdList, name)
    }

    imageNames, err := rbd.GetImageNames(ioctx)
    assert.NoError(t, err)

    sort.Strings(createdList)
    sort.Strings(imageNames)
    assert.Equal(t, createdList, imageNames)

    ioctx.Destroy()
    conn.Shutdown()
}
<commit_msg>rbd: fix test<commit_after>package rbd_test

import (
    "testing"
    "github.com/noahdesu/go-ceph/rados"
    "github.com/noahdesu/go-ceph/rbd"
    "github.com/stretchr/testify/assert"
    "os/exec"
    "sort"
)

func GetUUID() string {
    out, _ := exec.Command("uuidgen").Output()
    return string(out[:36])
}

func TestVersion(t *testing.T) {
    var major, minor, patch = rbd.Version()
    assert.False(t, major < 0 || major > 1000, "invalid major")
    assert.False(t, minor < 0 || minor > 1000, "invalid minor")
    assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestGetImageNames(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    poolname := GetUUID()
    err := conn.MakePool(poolname)
    assert.NoError(t, err)

    ioctx, err := conn.OpenIOContext(poolname)
    assert.NoError(t, err)

    createdList := []string{}
    for i := 0; i < 10; i++ {
        name := GetUUID()
        _, err := rbd.Create(ioctx, name, 1<<22)
        assert.NoError(t, err)
        createdList = append(createdList, name)
    }

    imageNames, err := rbd.GetImageNames(ioctx)
    assert.NoError(t, err)

    sort.Strings(createdList)
    sort.Strings(imageNames)
    assert.Equal(t, createdList, imageNames)

    ioctx.Destroy()
    conn.Shutdown()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"time"
)

// Response payload sent back to the requestor
type Response struct {
	Body  string            `json:"body"`
	Meta  map[string]string `json:"meta"`
	MSecs uint32            `json:"msecs"`
}

var (
	inputPath                     *string  = flag.String("input", "", "The file path to convert and exit; no server")
	listenAddr                    *string  = flag.String("addr", ":8888", "The address to listen on (e.g. 127.0.0.1:8888)")
	logLevel                      *uint    = flag.Uint("log-level", 0, "The verbosity of the log")
	readabilityLengthLow          *int     = flag.Int("readability-length-low", 70, "Sets the readability length low")
	readabilityLengthHigh         *int     = flag.Int("readability-length-high", 200, "Sets the readability length high")
	readabilityStopwordsLow       *float64 = flag.Float64("readability-stopwords-low", 0.2, "Sets the readability stopwords low")
	readabilityStopwordsHigh      *float64 = flag.Float64("readability-stopwords-high", 0.3, "Sets the readability stopwords high")
	readabilityMaxLinkDensity     *float64 = flag.Float64("readability-max-link-density", 0.2, "Sets the readability max link density")
	readabilityMaxHeadingDistance *int     = flag.Int("readability-max-heading-distance", 200, "Sets the readability max heading distance")
	readabilityUseClasses         *string  = flag.String("readability-use-classes", "good,neargood", "Comma separated list of readability classes to use")
)

// Determine the mime type by the file's extension
func mimeTypeByExtension(filename string) string {
	switch path.Ext(filename) {
	case ".doc":
		return "application/msword"
	case ".docx":
		return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
	case ".odt":
		return "application/vnd.oasis.opendocument.text"
	case ".pages":
		return "application/vnd.apple.pages"
	case ".pdf":
		return "application/pdf"
	case ".rtf":
		return "application/rtf"
	case ".xml":
		return "text/xml"
	case ".xhtml", ".html", ".htm":
		return "text/html"
	case ".txt":
		return "text/plain"
	}
	return "application/octet-stream"
}

// Convert a file to plain text & meta data
func convert(input io.Reader, mimeType string, readability bool) *Response {
	start := time.Now()

	var body string
	var meta map[string]string
	switch mimeType {
	case "application/msword", "application/vnd.ms-word":
		body, meta = ConvertDoc(input)

	case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
		body, meta = ConvertDocx(input)

	case "application/vnd.oasis.opendocument.text":
		body, meta = ConvertOdt(input)

	case "application/vnd.apple.pages", "application/x-iwork-pages-sffpages":
		body, meta = ConvertPages(input)

	case "application/pdf":
		body, meta = ConvertPdf(input)

	case "application/rtf", "application/x-rtf", "text/rtf", "text/richtext":
		body, meta = ConvertRtf(input)

	case "text/html":
		body, meta = ConvertHtml(input, readability)

	case "text/url":
		body, meta = ConvertUrl(input, readability)

	case "text/xml", "application/xml":
		body, meta = ConvertXml(input)

	case "text/plain":
		// TODO: Don't ignore the error.
		b, _ := ioutil.ReadAll(input)
		body = string(b)
	}

	return &Response{
		Body:  body,
		Meta:  meta,
		MSecs: uint32(time.Since(start) / time.Millisecond),
	}
}

func main() {
	flag.Parse()

	if *inputPath != "" {
		b, err := convertPath(*inputPath)
		if err != nil {
			log.Fatal("Cannot open file: ", err)
		}
		fmt.Print(string(b))
		return
	}
	serve()
}

// Convert a file given a path
func convertPath(path string) ([]byte, error) {
	mimeType := mimeTypeByExtension(path)
	if *logLevel >= 1 {
		log.Println("Converting file: " + path + " (" + mimeType + ")")
	}

	// Open file
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	// TODO: Don't ignore this error.
	b, _ := json.Marshal(convert(f, mimeType, false))
	if *logLevel >= 2 {
		log.Println(string(b))
	}
	return b, nil
}

// Start the conversion web service
func serve() {
	http.HandleFunc("/convert", func(w http.ResponseWriter, r *http.Request) {
		// Get uploaded file
		file, info, err := r.FormFile("input")
		if err != nil {
			log.Println("File upload", err)
			return
		}
		defer file.Close()

		// Abort if file doesn't have a mime type
		if len(info.Header["Content-Type"]) == 0 {
			log.Println("No content type", info.Filename)
			return
		}

		// If a generic mime type was provided then use file extension to determine mimetype
		mimeType := info.Header["Content-Type"][0]
		if mimeType == "application/octet-stream" {
			mimeType = mimeTypeByExtension(info.Filename)
		}

		if *logLevel >= 1 {
			log.Println("Received file: " + info.Filename + " (" + mimeType + ")")
		}

		// Readability flag. Currently only used for HTML
		var readability bool
		if r.FormValue("readability") == "1" {
			readability = true
			if *logLevel >= 2 {
				log.Println("Readability is on")
			}
		}

		jsonStr, _ := json.Marshal(convert(file, mimeType, readability))
		if *logLevel >= 2 {
			log.Println(string(jsonStr))
		}
		fmt.Fprintf(w, "%s", jsonStr)
	})

	// Start webserver
	log.Println("Setting log level to", *logLevel)
	log.Println("Starting Sajari convert on", *listenAddr)
	log.Fatal(http.ListenAndServe(*listenAddr, nil))
}
<commit_msg>Added 'path' form variable.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"time"
)

// Response payload sent back to the requestor
type Response struct {
	Body  string            `json:"body"`
	Meta  map[string]string `json:"meta"`
	MSecs uint32            `json:"msecs"`
}

var (
	inputPath                     *string  = flag.String("input", "", "The file path to convert and exit; no server")
	listenAddr                    *string  = flag.String("addr", ":8888", "The address to listen on (e.g. 127.0.0.1:8888)")
	logLevel                      *uint    = flag.Uint("log-level", 0, "The verbosity of the log")
	readabilityLengthLow          *int     = flag.Int("readability-length-low", 70, "Sets the readability length low")
	readabilityLengthHigh         *int     = flag.Int("readability-length-high", 200, "Sets the readability length high")
	readabilityStopwordsLow       *float64 = flag.Float64("readability-stopwords-low", 0.2, "Sets the readability stopwords low")
	readabilityStopwordsHigh      *float64 = flag.Float64("readability-stopwords-high", 0.3, "Sets the readability stopwords high")
	readabilityMaxLinkDensity     *float64 = flag.Float64("readability-max-link-density", 0.2, "Sets the readability max link density")
	readabilityMaxHeadingDistance *int     = flag.Int("readability-max-heading-distance", 200, "Sets the readability max heading distance")
	readabilityUseClasses         *string  = flag.String("readability-use-classes", "good,neargood", "Comma separated list of readability classes to use")
)

// Determine the mime type by the file's extension
func mimeTypeByExtension(filename string) string {
	switch path.Ext(filename) {
	case ".doc":
		return "application/msword"
	case ".docx":
		return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
	case ".odt":
		return "application/vnd.oasis.opendocument.text"
	case ".pages":
		return "application/vnd.apple.pages"
	case ".pdf":
		return "application/pdf"
	case ".rtf":
		return "application/rtf"
	case ".xml":
		return "text/xml"
	case ".xhtml", ".html", ".htm":
		return "text/html"
	case ".txt":
		return "text/plain"
	}
	return "application/octet-stream"
}

// Convert a file to plain text & meta data
func convert(input io.Reader, mimeType string, readability bool) *Response {
	start := time.Now()

	var body string
	var meta map[string]string
	switch mimeType {
	case "application/msword", "application/vnd.ms-word":
		body, meta = ConvertDoc(input)

	case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
		body, meta = ConvertDocx(input)

	case "application/vnd.oasis.opendocument.text":
		body, meta = ConvertOdt(input)

	case "application/vnd.apple.pages", "application/x-iwork-pages-sffpages":
		body, meta = ConvertPages(input)

	case "application/pdf":
		body, meta = ConvertPdf(input)

	case "application/rtf", "application/x-rtf", "text/rtf", "text/richtext":
		body, meta = ConvertRtf(input)

	case "text/html":
		body, meta = ConvertHtml(input, readability)

	case "text/url":
		body, meta = ConvertUrl(input, readability)

	case "text/xml", "application/xml":
		body, meta = ConvertXml(input)

	case "text/plain":
		// TODO: Don't ignore the error.
		b, _ := ioutil.ReadAll(input)
		body = string(b)
	}

	return &Response{
		Body:  body,
		Meta:  meta,
		MSecs: uint32(time.Since(start) / time.Millisecond),
	}
}

func main() {
	flag.Parse()

	if *inputPath != "" {
		b, err := convertPath(*inputPath, false)
		if err != nil {
			log.Fatal("Cannot open file: ", err)
		}
		fmt.Print(string(b))
		return
	}
	serve()
}

// Convert a file given a path
func convertPath(path string, readability bool) ([]byte, error) {
	mimeType := mimeTypeByExtension(path)
	if *logLevel >= 1 {
		log.Println("Converting file: " + path + " (" + mimeType + ")")
	}

	// Open file
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	// TODO: Don't ignore this error.
	b, _ := json.Marshal(convert(f, mimeType, readability))
	if *logLevel >= 2 {
		log.Println(string(b))
	}
	return b, nil
}

// Start the conversion web service
func serve() {
	http.HandleFunc("/convert", func(w http.ResponseWriter, r *http.Request) {
		// Readability flag. Currently only used for HTML
		var readability bool
		if r.FormValue("readability") == "1" {
			readability = true
			if *logLevel >= 2 {
				log.Println("Readability is on")
			}
		}

		path := r.FormValue("path")
		if path != "" {
			b, err := convertPath(path, readability)
			if err != nil {
				// TODO: return a sensible status code for errors like this.
				log.Printf("error converting path '%v': %v", path, err)
				return
			}
			w.Write(b)
			return
		}

		// Get uploaded file
		file, info, err := r.FormFile("input")
		if err != nil {
			log.Println("File upload", err)
			return
		}
		defer file.Close()

		// Abort if file doesn't have a mime type
		if len(info.Header["Content-Type"]) == 0 {
			log.Println("No content type", info.Filename)
			return
		}

		// If a generic mime type was provided then use file extension to determine mimetype
		mimeType := info.Header["Content-Type"][0]
		if mimeType == "application/octet-stream" {
			mimeType = mimeTypeByExtension(info.Filename)
		}

		if *logLevel >= 1 {
			log.Println("Received file: " + info.Filename + " (" + mimeType + ")")
		}

		jsonStr, _ := json.Marshal(convert(file, mimeType, readability))
		if *logLevel >= 2 {
			log.Println(string(jsonStr))
		}
		fmt.Fprintf(w, "%s", jsonStr)
	})

	// Start webserver
	log.Println("Setting log level to", *logLevel)
	log.Println("Starting Sajari convert on", *listenAddr)
	log.Fatal(http.ListenAndServe(*listenAddr, nil))
}
<|endoftext|>


<commit_before>// Copyright 2016 The nvim-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 command

import (
	"path/filepath"
	"reflect"
	"testing"

	"nvim-go/ctx"
	"nvim-go/nvimutil"

	"github.com/neovim/go-client/nvim"
)

var testLintDir = filepath.Join(testCwd, "../testdata", "go", "src", "lint")

func TestCommands_Lint(t *testing.T) {
	type fields struct {
		Nvim *nvim.Nvim
		ctx  *ctx.Context
	}
	type args struct {
		args []string
		file string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    []*nvim.QuickfixError
		wantErr bool
	}{
		{
			name: "no suggest(go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "blank-import-main.go")),
			},
			args: args{
				file: filepath.Join(testLintDir, "blank-import-main.go"),
			},
			want:    nil,
			wantErr: false,
		},
		{
			name: "2 suggest(go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "time.go")),
			},
			args: args{
				args: []string{"%"},
				file: filepath.Join(testLintDir, "time.go"),
			},
			want: []*nvim.QuickfixError{&nvim.QuickfixError{
				FileName: "time.go",
				LNum:     11,
				Col:      5,
				Text:     "var rpcTimeoutMsec is of type *time.Duration; don't use unit-specific suffix \"Msec\"",
			}, &nvim.QuickfixError{
				FileName: "time.go",
				LNum:     13,
				Col:      5,
				Text:     "var timeoutSecs is of type time.Duration; don't use unit-specific suffix \"Secs\"",
			}},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := ctx.NewContext()
			c := NewCommand(tt.fields.Nvim, ctx)
			c.Nvim.SetCurrentDirectory(filepath.Dir(tt.args.file))

			got, err := c.Lint(tt.args.args, tt.args.file)
			if (err != nil) != tt.wantErr {
				t.Errorf("%q. Commands.Lint(%v, %v) error = %v, wantErr %v", tt.name, tt.args.args, tt.args.file, err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Logf("%+v\n%+v", got[0], got[1])
				t.Errorf("%q. Commands.Lint(%v, %v) = %v, want %v", tt.name, tt.args.args, tt.args.file, got, tt.want)
			}
		})
	}
}

func TestCommands_cmdLintComplete(t *testing.T) {
	type fields struct {
		Nvim *nvim.Nvim
		ctx  *ctx.Context
	}
	type args struct {
		a   *nvim.CommandCompletionArgs
		cwd string
	}
	tests := []struct {
		name         string
		fields       fields
		args         args
		wantFilelist []string
		wantErr      bool
	}{
		{
			name: "lint dir - no args (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: testLintDir,
			},
			wantFilelist: []string{"blank-import-main.go", "make.go", "time.go"},
		},
		{
			name: "lint dir - 'ma' (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a: &nvim.CommandCompletionArgs{
					ArgLead: "ma",
				},
				cwd: testLintDir,
			},
			wantFilelist: []string{"make.go"},
		},
		{
			name: "astdump (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, astdumpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: astdump,
			},
			wantFilelist: []string{"astdump.go"},
		},
		{
			name: "gsftp (gb)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, gsftpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: gsftp,
			},
			wantFilelist: []string{"main.go"},
		},
	}
	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			tt.fields.ctx = ctx.NewContext()
			c := NewCommand(tt.fields.Nvim, tt.fields.ctx)

			gotFilelist, err := c.cmdLintComplete(tt.args.a, tt.args.cwd)
			if (err != nil) != tt.wantErr {
				t.Errorf("%q. Commands.cmdLintComplete(%v, %v) error = %v, wantErr %v", tt.name, tt.args.a, tt.args.cwd, err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(gotFilelist, tt.wantFilelist) {
				t.Errorf("%q. Commands.cmdLintComplete(%v, %v) = %v, want %v", tt.name, tt.args.a, tt.args.cwd, gotFilelist, tt.wantFilelist)
			}
		})
	}
}
<commit_msg>command/lint: remove unnecessary test log output<commit_after>// Copyright 2016 The nvim-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 command

import (
	"path/filepath"
	"reflect"
	"testing"

	"nvim-go/ctx"
	"nvim-go/nvimutil"

	"github.com/neovim/go-client/nvim"
)

var testLintDir = filepath.Join(testCwd, "../testdata", "go", "src", "lint")

func TestCommands_Lint(t *testing.T) {
	type fields struct {
		Nvim *nvim.Nvim
		ctx  *ctx.Context
	}
	type args struct {
		args []string
		file string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    []*nvim.QuickfixError
		wantErr bool
	}{
		{
			name: "no suggest(go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "blank-import-main.go")),
			},
			args: args{
				file: filepath.Join(testLintDir, "blank-import-main.go"),
			},
			want:    nil,
			wantErr: false,
		},
		{
			name: "2 suggest(go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "time.go")),
			},
			args: args{
				args: []string{"%"},
				file: filepath.Join(testLintDir, "time.go"),
			},
			want: []*nvim.QuickfixError{&nvim.QuickfixError{
				FileName: "time.go",
				LNum:     11,
				Col:      5,
				Text:     "var rpcTimeoutMsec is of type *time.Duration; don't use unit-specific suffix \"Msec\"",
			}, &nvim.QuickfixError{
				FileName: "time.go",
				LNum:     13,
				Col:      5,
				Text:     "var timeoutSecs is of type time.Duration; don't use unit-specific suffix \"Secs\"",
			}},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := ctx.NewContext()
			c := NewCommand(tt.fields.Nvim, ctx)
			c.Nvim.SetCurrentDirectory(filepath.Dir(tt.args.file))

			got, err := c.Lint(tt.args.args, tt.args.file)
			if (err != nil) != tt.wantErr {
				t.Errorf("%q. Commands.Lint(%v, %v) error = %v, wantErr %v", tt.name, tt.args.args, tt.args.file, err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("%q. Commands.Lint(%v, %v) = %v, want %v", tt.name, tt.args.args, tt.args.file, got, tt.want)
			}
		})
	}
}

func TestCommands_cmdLintComplete(t *testing.T) {
	type fields struct {
		Nvim *nvim.Nvim
		ctx  *ctx.Context
	}
	type args struct {
		a   *nvim.CommandCompletionArgs
		cwd string
	}
	tests := []struct {
		name         string
		fields       fields
		args         args
		wantFilelist []string
		wantErr      bool
	}{
		{
			name: "lint dir - no args (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: testLintDir,
			},
			wantFilelist: []string{"blank-import-main.go", "make.go", "time.go"},
		},
		{
			name: "lint dir - 'ma' (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, filepath.Join(testLintDir, "make.go")),
			},
			args: args{
				a: &nvim.CommandCompletionArgs{
					ArgLead: "ma",
				},
				cwd: testLintDir,
			},
			wantFilelist: []string{"make.go"},
		},
		{
			name: "astdump (go)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, astdumpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: astdump,
			},
			wantFilelist: []string{"astdump.go"},
		},
		{
			name: "gsftp (gb)",
			fields: fields{
				Nvim: nvimutil.TestNvim(t, gsftpMain),
			},
			args: args{
				a:   new(nvim.CommandCompletionArgs),
				cwd: gsftp,
			},
			wantFilelist: []string{"main.go"},
		},
	}
	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			tt.fields.ctx = ctx.NewContext()
			c := NewCommand(tt.fields.Nvim, tt.fields.ctx)

			gotFilelist, err := c.cmdLintComplete(tt.args.a, tt.args.cwd)
			if (err != nil) != tt.wantErr {
				t.Errorf("%q. Commands.cmdLintComplete(%v, %v) error = %v, wantErr %v", tt.name, tt.args.a, tt.args.cwd, err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(gotFilelist, tt.wantFilelist) {
				t.Errorf("%q. Commands.cmdLintComplete(%v, %v) = %v, want %v", tt.name, tt.args.a, tt.args.cwd, gotFilelist, tt.wantFilelist)
			}
		})
	}
}
<|endoftext|>


<commit_before>package catalog

import (
	"fmt"
	"github.com/vincent3i/beego-blog/g"
	//.表示可以不用带包名访问里面的变量方法
	. "github.com/vincent3i/beego-blog/models"
	"github.com/astaxie/beego/orm"
	"github.com/qiniu/api/rs"
)

func OneById(id int64) *Catalog {
	if id == 0 {
		return nil
	}

	key := fmt.Sprintf("%d", id)
	val := g.CatalogCacheGet(key)
	if val == nil {
		if cp := OneByIdInDB(id); cp != nil {
			g.CatalogCachePut(key, *cp)
			return cp
		} else {
			return nil
		}
	}
	ret := val.(Catalog)
	return &ret
}

func OneByIdInDB(id int64) *Catalog {
	if id == 0 {
		return nil
	}

	c := Catalog{Id: id}
	err := orm.NewOrm().Read(&c, "Id")
	if err != nil {
		return nil
	}
	return &c
}

func IdByIdent(ident string) int64 {
	if ident == "" {
		return 0
	}

	val := g.CatalogCacheGet(ident)
	if val == nil {
		if cp := OneByIdentInDB(ident); cp != nil {
			g.CatalogCachePut(ident, cp.Id)
			return cp.Id
		} else {
			return 0
		}
	}

	return val.(int64)
}

func IdentExists(ident string) bool {
	id := IdByIdent(ident)
	return id > 0
}

func OneByIdent(ident string) *Catalog {
	id := IdByIdent(ident)
	return OneById(id)
}

func OneByIdentInDB(ident string) *Catalog {
	if ident == "" {
		return nil
	}

	c := Catalog{Ident: ident}
	err := orm.NewOrm().Read(&c, "Ident")
	if err != nil {
		return nil
	}

	return &c
}

func AllIdsInDB() []int64 {
	var catalogs []Catalog
	Catalogs().OrderBy("-DisplayOrder").All(&catalogs, "Id")
	size := len(catalogs)
	if size == 0 {
		return []int64{}
	}

	ret := make([]int64, size)
	for i := 0; i < size; i++ {
		ret[i] = catalogs[i].Id
	}

	return ret
}

func AllIds() []int64 {
	val := g.CatalogCacheGet("ids")
	if val == nil {
		if ids := AllIdsInDB(); len(ids) != 0 {
			g.CatalogCachePut("ids", ids)
			return ids
		} else {
			return []int64{}
		}
	}

	return val.([]int64)
}

func All() []*Catalog {
	ids := AllIds()
	size := len(ids)
	if size == 0 {
		return []*Catalog{}
	}

	ret := make([]*Catalog, size)
	for i := 0; i < size; i++ {
		ret[i] = OneById(ids[i])

		//私有域名访问
		//http://developer.qiniu.com/docs/v6/api/reference/security/download-token.html
		//http://developer.qiniu.com/docs/v6/sdk/go-sdk.html#io-get-private
		g.Log.Debug("Image url is %s", ret[i].ImgUrl)
		ret[i].ImgUrl = downloadUrl(g.QiniuScope, string(ret[i].ImgUrl[len("http://vincent/qiniudn.com/"):]))
		g.Log.Debug("Image url is %s", ret[i].ImgUrl)
	}
	return ret
}

func Save(this *Catalog) (int64, error) {
	if IdentExists(this.Ident) {
		return 0, fmt.Errorf("catalog english identity exists")
	}
	num, err := orm.NewOrm().Insert(this)
	if err == nil {
		g.CatalogCacheDel("ids")
	}

	return num, err
}

func Del(c *Catalog) error {
	num, err := orm.NewOrm().Delete(c)
	if err != nil {
		return err
	}

	if num > 0 {
		g.CatalogCacheDel("ids")
	}
	return nil
}

func Update(this *Catalog) error {
	if this.Id == 0 {
		return fmt.Errorf("primary key id not set")
	}
	_, err := orm.NewOrm().Update(this)
	if err == nil {
		g.CatalogCacheDel(fmt.Sprintf("%d", this.Id))
	}
	return err
}

func Catalogs() orm.QuerySeter {
	return orm.NewOrm().QueryTable(new(Catalog))
}

func downloadUrl(domain, key string) string {
    baseUrl := rs.MakeBaseUrl(domain, key)
    policy := rs.GetPolicy{}
    return  policy.MakeRequest(baseUrl, nil)
}<commit_msg>go todo<commit_after>package catalog

import (
	"fmt"
	"github.com/vincent3i/beego-blog/g"
	//.表示可以不用带包名访问里面的变量方法
	. "github.com/vincent3i/beego-blog/models"
	"github.com/astaxie/beego/orm"
	"github.com/qiniu/api/rs"
)

func OneById(id int64) *Catalog {
	if id == 0 {
		return nil
	}

	key := fmt.Sprintf("%d", id)
	val := g.CatalogCacheGet(key)
	if val == nil {
		if cp := OneByIdInDB(id); cp != nil {
			g.CatalogCachePut(key, *cp)
			return cp
		} else {
			return nil
		}
	}
	ret := val.(Catalog)
	return &ret
}

func OneByIdInDB(id int64) *Catalog {
	if id == 0 {
		return nil
	}

	c := Catalog{Id: id}
	err := orm.NewOrm().Read(&c, "Id")
	if err != nil {
		return nil
	}
	return &c
}

func IdByIdent(ident string) int64 {
	if ident == "" {
		return 0
	}

	val := g.CatalogCacheGet(ident)
	if val == nil {
		if cp := OneByIdentInDB(ident); cp != nil {
			g.CatalogCachePut(ident, cp.Id)
			return cp.Id
		} else {
			return 0
		}
	}

	return val.(int64)
}

func IdentExists(ident string) bool {
	id := IdByIdent(ident)
	return id > 0
}

func OneByIdent(ident string) *Catalog {
	id := IdByIdent(ident)
	return OneById(id)
}

func OneByIdentInDB(ident string) *Catalog {
	if ident == "" {
		return nil
	}

	c := Catalog{Ident: ident}
	err := orm.NewOrm().Read(&c, "Ident")
	if err != nil {
		return nil
	}

	return &c
}

func AllIdsInDB() []int64 {
	var catalogs []Catalog
	Catalogs().OrderBy("-DisplayOrder").All(&catalogs, "Id")
	size := len(catalogs)
	if size == 0 {
		return []int64{}
	}

	ret := make([]int64, size)
	for i := 0; i < size; i++ {
		ret[i] = catalogs[i].Id
	}

	return ret
}

func AllIds() []int64 {
	val := g.CatalogCacheGet("ids")
	if val == nil {
		if ids := AllIdsInDB(); len(ids) != 0 {
			g.CatalogCachePut("ids", ids)
			return ids
		} else {
			return []int64{}
		}
	}

	return val.([]int64)
}

func All() []*Catalog {
	ids := AllIds()
	size := len(ids)
	if size == 0 {
		return []*Catalog{}
	}

	ret := make([]*Catalog, size)
	for i := 0; i < size; i++ {
		ret[i] = OneById(ids[i])

		//私有域名访问
		//http://developer.qiniu.com/docs/v6/api/reference/security/download-token.html
		//http://developer.qiniu.com/docs/v6/sdk/go-sdk.html#io-get-private
		// TODO
		g.Log.Debug("Image url is %s", ret[i].ImgUrl)
		ret[i].ImgUrl = downloadUrl(g.QiniuScope, string(ret[i].ImgUrl[len("http://vincent/qiniudn.com/"):]))
		g.Log.Debug("Image url is %s", ret[i].ImgUrl)
	}
	return ret
}

func Save(this *Catalog) (int64, error) {
	if IdentExists(this.Ident) {
		return 0, fmt.Errorf("catalog english identity exists")
	}
	num, err := orm.NewOrm().Insert(this)
	if err == nil {
		g.CatalogCacheDel("ids")
	}

	return num, err
}

func Del(c *Catalog) error {
	num, err := orm.NewOrm().Delete(c)
	if err != nil {
		return err
	}

	if num > 0 {
		g.CatalogCacheDel("ids")
	}
	return nil
}

func Update(this *Catalog) error {
	if this.Id == 0 {
		return fmt.Errorf("primary key id not set")
	}
	_, err := orm.NewOrm().Update(this)
	if err == nil {
		g.CatalogCacheDel(fmt.Sprintf("%d", this.Id))
	}
	return err
}

func Catalogs() orm.QuerySeter {
	return orm.NewOrm().QueryTable(new(Catalog))
}

func downloadUrl(domain, key string) string {
    baseUrl := rs.MakeBaseUrl(domain, key)
    policy := rs.GetPolicy{}
    return  policy.MakeRequest(baseUrl, nil)
}<|endoftext|>


<commit_before>package gif

import (
	"bytes"
	"compress/lzw"
	"image"
	"image/color"
	"reflect"
	"testing"
)

func TestDecode(t *testing.T) {
	// header and trailer are parts of a valid 2x1 GIF image.
	const (
		header = "GIF89a" +
			"\x02\x00\x01\x00" + // width=2, height=1
			"\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
			"\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
		trailer = "\x3b"
	)

	// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
	lzwEncode := func(n int) []byte {
		b := &bytes.Buffer{}
		w := lzw.NewWriter(b, lzw.LSB, 2)
		w.Write(make([]byte, n))
		w.Close()
		return b.Bytes()
	}

	testCases := []struct {
		nPix    int  // The number of pixels in the image data.
		extra   bool // Whether to write an extra block after the LZW-encoded data.
		wantErr error
	}{
		{0, false, errNotEnough},
		{1, false, errNotEnough},
		{2, false, nil},
		{2, true, errTooMuch},
		{3, false, errTooMuch},
	}
	for _, tc := range testCases {
		b := &bytes.Buffer{}
		b.WriteString(header)
		// Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
		// then this should result in an invalid GIF image. First, write a
		// magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
		// byte, and 2-bit LZW literals.
		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
		if tc.nPix > 0 {
			enc := lzwEncode(tc.nPix)
			if len(enc) > 0xff {
				t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
				continue
			}
			b.WriteByte(byte(len(enc)))
			b.Write(enc)
		}
		if tc.extra {
			b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
		}
		b.WriteByte(0x00) // An empty block signifies the end of the image data.
		b.WriteString(trailer)

		got, err := Decode(b)
		if err != tc.wantErr {
			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
		}

		if tc.wantErr != nil {
			continue
		}
		want := &image.Paletted{
			Pix:    []uint8{0, 0},
			Stride: 2,
			Rect:   image.Rect(0, 0, 2, 1),
			Palette: color.Palette{
				color.RGBA{0x10, 0x20, 0x30, 0xff},
				color.RGBA{0x40, 0x50, 0x60, 0xff},
			},
		}
		if !reflect.DeepEqual(got, want) {
			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, got, want)
		}
	}
}

// testGIF is a simple GIF that we can modify to test different scenarios.
var testGIF = []byte{
	'G', 'I', 'F', '8', '9', 'a',
	1, 0, 1, 0, // w=1, h=1 (6)
	128, 0, 0, // headerFields, bg, aspect (10)
	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
	// frame 1 (0,0 - 1,1)
	0x2c,
	0x00, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x01, 0x00, // (32)
	0x00,
	0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
	// trailer
	0x3b,
}

func try(t *testing.T, b []byte, want string) {
	_, err := DecodeAll(bytes.NewReader(b))
	var got string
	if err != nil {
		got = err.Error()
	}
	if got != want {
		t.Fatalf("got %v, want %v", got, want)
	}
}

func TestBounds(t *testing.T) {
	// Make the bounds too big, just by one.
	testGIF[32] = 2
	want := "gif: frame bounds larger than image bounds"
	try(t, testGIF, want)

	// Make the bounds too small; does not trigger bounds
	// check, but now there's too much data.
	testGIF[32] = 0
	want = "gif: too much image data"
	try(t, testGIF, want)
	testGIF[32] = 1

	// Make the bounds really big, expect an error.
	want = "gif: frame bounds larger than image bounds"
	for i := 0; i < 4; i++ {
		testGIF[32+i] = 0xff
	}
	try(t, testGIF, want)
}
<commit_msg>image/gif: make test repeatable<commit_after>package gif

import (
	"bytes"
	"compress/lzw"
	"image"
	"image/color"
	"reflect"
	"testing"
)

func TestDecode(t *testing.T) {
	// header and trailer are parts of a valid 2x1 GIF image.
	const (
		header = "GIF89a" +
			"\x02\x00\x01\x00" + // width=2, height=1
			"\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
			"\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
		trailer = "\x3b"
	)

	// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
	lzwEncode := func(n int) []byte {
		b := &bytes.Buffer{}
		w := lzw.NewWriter(b, lzw.LSB, 2)
		w.Write(make([]byte, n))
		w.Close()
		return b.Bytes()
	}

	testCases := []struct {
		nPix    int  // The number of pixels in the image data.
		extra   bool // Whether to write an extra block after the LZW-encoded data.
		wantErr error
	}{
		{0, false, errNotEnough},
		{1, false, errNotEnough},
		{2, false, nil},
		{2, true, errTooMuch},
		{3, false, errTooMuch},
	}
	for _, tc := range testCases {
		b := &bytes.Buffer{}
		b.WriteString(header)
		// Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
		// then this should result in an invalid GIF image. First, write a
		// magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
		// byte, and 2-bit LZW literals.
		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
		if tc.nPix > 0 {
			enc := lzwEncode(tc.nPix)
			if len(enc) > 0xff {
				t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
				continue
			}
			b.WriteByte(byte(len(enc)))
			b.Write(enc)
		}
		if tc.extra {
			b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
		}
		b.WriteByte(0x00) // An empty block signifies the end of the image data.
		b.WriteString(trailer)

		got, err := Decode(b)
		if err != tc.wantErr {
			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
		}

		if tc.wantErr != nil {
			continue
		}
		want := &image.Paletted{
			Pix:    []uint8{0, 0},
			Stride: 2,
			Rect:   image.Rect(0, 0, 2, 1),
			Palette: color.Palette{
				color.RGBA{0x10, 0x20, 0x30, 0xff},
				color.RGBA{0x40, 0x50, 0x60, 0xff},
			},
		}
		if !reflect.DeepEqual(got, want) {
			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, got, want)
		}
	}
}

// testGIF is a simple GIF that we can modify to test different scenarios.
var testGIF = []byte{
	'G', 'I', 'F', '8', '9', 'a',
	1, 0, 1, 0, // w=1, h=1 (6)
	128, 0, 0, // headerFields, bg, aspect (10)
	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
	// frame 1 (0,0 - 1,1)
	0x2c,
	0x00, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x01, 0x00, // (32)
	0x00,
	0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
	// trailer
	0x3b,
}

func try(t *testing.T, b []byte, want string) {
	_, err := DecodeAll(bytes.NewReader(b))
	var got string
	if err != nil {
		got = err.Error()
	}
	if got != want {
		t.Fatalf("got %v, want %v", got, want)
	}
}

func TestBounds(t *testing.T) {
	// make a local copy of testGIF
	gif := make([]byte, len(testGIF))
	copy(gif, testGIF)
	// Make the bounds too big, just by one.
	gif[32] = 2
	want := "gif: frame bounds larger than image bounds"
	try(t, gif, want)

	// Make the bounds too small; does not trigger bounds
	// check, but now there's too much data.
	gif[32] = 0
	want = "gif: too much image data"
	try(t, gif, want)
	gif[32] = 1

	// Make the bounds really big, expect an error.
	want = "gif: frame bounds larger than image bounds"
	for i := 0; i < 4; i++ {
		gif[32+i] = 0xff
	}
	try(t, gif, want)
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// Netlink sockets and messages

package syscall

import (
	"unsafe"
)

// Round the length of a netlink message up to align it properly.
func nlmAlignOf(msglen int) int {
	return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
}

// Round the length of a netlink route attribute up to align it
// properly.
func rtaAlignOf(attrlen int) int {
	return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
}

// NetlinkRouteRequest represents the request message to receive
// routing and link states from the kernel.
type NetlinkRouteRequest struct {
	Header NlMsghdr
	Data   RtGenmsg
}

func (rr *NetlinkRouteRequest) toWireFormat() []byte {
	b := make([]byte, rr.Header.Len)
	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
	b[16] = byte(rr.Data.Family)
	return b
}

func newNetlinkRouteRequest(proto, seq, family int) []byte {
	rr := &NetlinkRouteRequest{}
	rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
	rr.Header.Type = uint16(proto)
	rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
	rr.Header.Seq = uint32(seq)
	rr.Data.Family = uint8(family)
	return rr.toWireFormat()
}

// NetlinkRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
func NetlinkRIB(proto, family int) ([]byte, error) {
	var (
		lsanl SockaddrNetlink
		tab   []byte
	)

	s, e := Socket(AF_NETLINK, SOCK_RAW, 0)
	if e != nil {
		return nil, e
	}
	defer Close(s)

	lsanl.Family = AF_NETLINK
	e = Bind(s, &lsanl)
	if e != nil {
		return nil, e
	}

	seq := 1
	wb := newNetlinkRouteRequest(proto, seq, family)
	e = Sendto(s, wb, 0, &lsanl)
	if e != nil {
		return nil, e
	}

	for {
		var (
			rb  []byte
			nr  int
			lsa Sockaddr
		)

		rb = make([]byte, Getpagesize())
		nr, _, e = Recvfrom(s, rb, 0)
		if e != nil {
			return nil, e
		}
		if nr < NLMSG_HDRLEN {
			return nil, EINVAL
		}
		rb = rb[:nr]
		tab = append(tab, rb...)

		msgs, _ := ParseNetlinkMessage(rb)
		for _, m := range msgs {
			if lsa, e = Getsockname(s); e != nil {
				return nil, e
			}
			switch v := lsa.(type) {
			case *SockaddrNetlink:
				if m.Header.Seq != uint32(seq) || m.Header.Pid != v.Pid {
					return nil, EINVAL
				}
			default:
				return nil, EINVAL
			}
			if m.Header.Type == NLMSG_DONE {
				goto done
			}
			if m.Header.Type == NLMSG_ERROR {
				return nil, EINVAL
			}
		}
	}

done:
	return tab, nil
}

// NetlinkMessage represents the netlink message.
type NetlinkMessage struct {
	Header NlMsghdr
	Data   []byte
}

// ParseNetlinkMessage parses buf as netlink messages and returns
// the slice containing the NetlinkMessage structs.
func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, error) {
	var (
		h    *NlMsghdr
		dbuf []byte
		dlen int
		e    error
		msgs []NetlinkMessage
	)

	for len(buf) >= NLMSG_HDRLEN {
		h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
		if e != nil {
			break
		}
		m := NetlinkMessage{}
		m.Header = *h
		m.Data = dbuf[:int(h.Len)-NLMSG_HDRLEN]
		msgs = append(msgs, m)
		buf = buf[dlen:]
	}

	return msgs, e
}

func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, error) {
	h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
	if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(buf) {
		return nil, nil, 0, EINVAL
	}
	return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}

// NetlinkRouteAttr represents the netlink route attribute.
type NetlinkRouteAttr struct {
	Attr  RtAttr
	Value []byte
}

// ParseNetlinkRouteAttr parses msg's payload as netlink route
// attributes and returns the slice containing the NetlinkRouteAttr
// structs.
func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, error) {
	var (
		buf   []byte
		a     *RtAttr
		alen  int
		vbuf  []byte
		e     error
		attrs []NetlinkRouteAttr
	)

	switch msg.Header.Type {
	case RTM_NEWLINK, RTM_DELLINK:
		buf = msg.Data[SizeofIfInfomsg:]
	case RTM_NEWADDR, RTM_DELADDR:
		buf = msg.Data[SizeofIfAddrmsg:]
	case RTM_NEWROUTE, RTM_DELROUTE:
		buf = msg.Data[SizeofRtMsg:]
	default:
		return nil, EINVAL
	}

	for len(buf) >= SizeofRtAttr {
		a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
		if e != nil {
			break
		}
		ra := NetlinkRouteAttr{}
		ra.Attr = *a
		ra.Value = vbuf[:int(a.Len)-SizeofRtAttr]
		attrs = append(attrs, ra)
		buf = buf[alen:]
	}

	return attrs, nil
}

func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, error) {
	h := (*RtAttr)(unsafe.Pointer(&buf[0]))
	if int(h.Len) < SizeofRtAttr || int(h.Len) > len(buf) {
		return nil, nil, 0, EINVAL
	}
	return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), nil
}
<commit_msg>syscall: simplify netlink sockets<commit_after>// Copyright 2011 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.

// Netlink sockets and messages

package syscall

import "unsafe"

// Round the length of a netlink message up to align it properly.
func nlmAlignOf(msglen int) int {
	return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
}

// Round the length of a netlink route attribute up to align it
// properly.
func rtaAlignOf(attrlen int) int {
	return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
}

// NetlinkRouteRequest represents a request message to receive routing
// and link states from the kernel.
type NetlinkRouteRequest struct {
	Header NlMsghdr
	Data   RtGenmsg
}

func (rr *NetlinkRouteRequest) toWireFormat() []byte {
	b := make([]byte, rr.Header.Len)
	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
	b[16] = byte(rr.Data.Family)
	return b
}

func newNetlinkRouteRequest(proto, seq, family int) []byte {
	rr := &NetlinkRouteRequest{}
	rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
	rr.Header.Type = uint16(proto)
	rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
	rr.Header.Seq = uint32(seq)
	rr.Data.Family = uint8(family)
	return rr.toWireFormat()
}

// NetlinkRIB returns routing information base, as known as RIB, which
// consists of network facility information, states and parameters.
func NetlinkRIB(proto, family int) ([]byte, error) {
	s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
	if err != nil {
		return nil, err
	}
	defer Close(s)
	lsa := &SockaddrNetlink{Family: AF_NETLINK}
	if err := Bind(s, lsa); err != nil {
		return nil, err
	}
	wb := newNetlinkRouteRequest(proto, 1, family)
	if err := Sendto(s, wb, 0, lsa); err != nil {
		return nil, err
	}
	var tab []byte
done:
	for {
		rb := make([]byte, Getpagesize())
		nr, _, err := Recvfrom(s, rb, 0)
		if err != nil {
			return nil, err
		}
		if nr < NLMSG_HDRLEN {
			return nil, EINVAL
		}
		rb = rb[:nr]
		tab = append(tab, rb...)
		msgs, err := ParseNetlinkMessage(rb)
		if err != nil {
			return nil, err
		}
		for _, m := range msgs {
			lsa, err := Getsockname(s)
			if err != nil {
				return nil, err
			}
			switch v := lsa.(type) {
			case *SockaddrNetlink:
				if m.Header.Seq != 1 || m.Header.Pid != v.Pid {
					return nil, EINVAL
				}
			default:
				return nil, EINVAL
			}
			if m.Header.Type == NLMSG_DONE {
				break done
			}
			if m.Header.Type == NLMSG_ERROR {
				return nil, EINVAL
			}
		}
	}
	return tab, nil
}

// NetlinkMessage represents a netlink message.
type NetlinkMessage struct {
	Header NlMsghdr
	Data   []byte
}

// ParseNetlinkMessage parses b as an array of netlink messages and
// returns the slice containing the NetlinkMessage structures.
func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) {
	var msgs []NetlinkMessage
	for len(b) >= NLMSG_HDRLEN {
		h, dbuf, dlen, err := netlinkMessageHeaderAndData(b)
		if err != nil {
			return nil, err
		}
		m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]}
		msgs = append(msgs, m)
		b = b[dlen:]
	}
	return msgs, nil
}

func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) {
	h := (*NlMsghdr)(unsafe.Pointer(&b[0]))
	if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) {
		return nil, nil, 0, EINVAL
	}
	return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}

// NetlinkRouteAttr represents a netlink route attribute.
type NetlinkRouteAttr struct {
	Attr  RtAttr
	Value []byte
}

// ParseNetlinkRouteAttr parses m's payload as an array of netlink
// route attributes and returns the slice containing the
// NetlinkRouteAttr structures.
func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) {
	var b []byte
	switch m.Header.Type {
	case RTM_NEWLINK, RTM_DELLINK:
		b = m.Data[SizeofIfInfomsg:]
	case RTM_NEWADDR, RTM_DELADDR:
		b = m.Data[SizeofIfAddrmsg:]
	case RTM_NEWROUTE, RTM_DELROUTE:
		b = m.Data[SizeofRtMsg:]
	default:
		return nil, EINVAL
	}
	var attrs []NetlinkRouteAttr
	for len(b) >= SizeofRtAttr {
		a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
		if err != nil {
			return nil, err
		}
		ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]}
		attrs = append(attrs, ra)
		b = b[alen:]
	}
	return attrs, nil
}

func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) {
	a := (*RtAttr)(unsafe.Pointer(&b[0]))
	if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) {
		return nil, nil, 0, EINVAL
	}
	return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
}
<|endoftext|>


<commit_before>package host

import (
	"path/filepath"
	"testing"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
	"github.com/NebulousLabs/Sia/modules/gateway"
	"github.com/NebulousLabs/Sia/modules/miner"
	"github.com/NebulousLabs/Sia/modules/transactionpool"
	"github.com/NebulousLabs/Sia/modules/wallet"
	"github.com/NebulousLabs/Sia/types"
)

// A hostTester is the helper object for host testing, including helper modules
// and methods for controlling synchronization.
type hostTester struct {
	cs        modules.ConsensusSet
	gateway   modules.Gateway
	miner     modules.TestMiner
	tpool     modules.TransactionPool
	wallet    modules.Wallet
	walletKey crypto.TwofishKey

	host *Host

	persistDir string
}

// initWallet creates a wallet key, initializes the host wallet, unlocks it,
// and then stores the key in the host tester.
func (ht *hostTester) initWallet() error {
	// Create the keys for the wallet and unlock it.
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return err
	}
	ht.walletKey = key
	_, err = ht.wallet.Encrypt(key)
	if err != nil {
		return err
	}
	err = ht.wallet.Unlock(key)
	if err != nil {
		return err
	}
	return nil
}

// blankHostTester creates a host tester where the modules are created but no
// extra initialization has been done, for example no blocks have been mined
// and the wallet keys have not been created.
func blankHostTester(name string) (*hostTester, error) {
	testdir := build.TempDir(modules.HostDir, name)

	// Create the modules.
	g, err := gateway.New(":0", filepath.Join(testdir, modules.GatewayDir))
	if err != nil {
		return nil, err
	}
	cs, err := consensus.New(g, filepath.Join(testdir, modules.ConsensusDir))
	if err != nil {
		return nil, err
	}
	tp, err := transactionpool.New(cs, g)
	if err != nil {
		return nil, err
	}
	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, err
	}
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, err
	}
	h, err := New(cs, tp, w, ":0", filepath.Join(testdir, modules.HostDir))
	if err != nil {
		return nil, err
	}

	// Assemble all objects into a hostTester
	ht := &hostTester{
		cs:      cs,
		gateway: g,
		miner:   m,
		tpool:   tp,
		wallet:  w,

		host: h,

		persistDir: testdir,
	}

	return ht, nil
}

// newHostTester creates a host tester with an initialized wallet and money in
// that wallet.
func newHostTester(name string) (*hostTester, error) {
	// Create a blank host tester.
	ht, err := blankHostTester(name)
	if err != nil {
		return nil, err
	}

	// Initialize the wallet and mine blocks until the wallet has money.
	err = ht.initWallet()
	if err != nil {
		return nil, err
	}
	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
		_, err = ht.miner.AddBlock()
		if err != nil {
			return nil, err
		}
	}
	return ht, nil
}

// TestHostInitialization checks that the host intializes to sensisble default
// values.
func TestHostInitialization(t *testing.T) {
	// Create a blank host tester and check that the height is zero.
	bht, err := blankHostTester("TestHostInitialization")
	if err != nil {
		t.Fatal(err)
	}
	if bht.host.blockHeight != 0 {
		t.Error("host initialized to the wrong block height")
	}

	// Initialize the wallet so that a block can be mined, then mine a block
	// and check that it sets the host height to 1.
	err = bht.initWallet()
	if err != nil {
		t.Fatal(err)
	}
	_, err = bht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if bht.host.blockHeight != 1 {
		t.Fatal("block height did not increase correctly after first block mined")
	}
}

// TestStartupRescan probes the startupRescan function, verifying that it
// works in the naive case. The rescan is triggered manually.
func TestStartupRescan(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	ht, err := newHostTester("TestStartupRescan")
	if err != nil {
		t.Fatal(err)
	}

	// Check that the host's persistent variables have incorporated the first
	// few blocks.
	if ht.host.recentChange == (modules.ConsensusChangeID{}) || ht.host.blockHeight == 0 {
		t.Fatal("host variables do not indicate that the host is tracking the consensus set correctly")
	}
	oldChange := ht.host.recentChange
	oldHeight := ht.host.blockHeight

	// Corrupt the variables and perform a rescan to see if they reset
	// correctly.
	ht.host.recentChange[0]++
	ht.host.blockHeight += 100e3
	ht.cs.Unsubscribe(ht.host)
	err = ht.host.startupRescan()
	if err != nil {
		t.Fatal(err)
	}
	if oldChange != ht.host.recentChange || oldHeight != ht.host.blockHeight {
		t.Error("consensus tracking variables were not reset correctly after rescan")
	}
}
<commit_msg>add auto-rescan test<commit_after>package host

import (
	"path/filepath"
	"testing"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
	"github.com/NebulousLabs/Sia/modules/gateway"
	"github.com/NebulousLabs/Sia/modules/miner"
	"github.com/NebulousLabs/Sia/modules/transactionpool"
	"github.com/NebulousLabs/Sia/modules/wallet"
	"github.com/NebulousLabs/Sia/types"
)

// A hostTester is the helper object for host testing, including helper modules
// and methods for controlling synchronization.
type hostTester struct {
	cs        modules.ConsensusSet
	gateway   modules.Gateway
	miner     modules.TestMiner
	tpool     modules.TransactionPool
	wallet    modules.Wallet
	walletKey crypto.TwofishKey

	host *Host

	persistDir string
}

// initWallet creates a wallet key, initializes the host wallet, unlocks it,
// and then stores the key in the host tester.
func (ht *hostTester) initWallet() error {
	// Create the keys for the wallet and unlock it.
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return err
	}
	ht.walletKey = key
	_, err = ht.wallet.Encrypt(key)
	if err != nil {
		return err
	}
	err = ht.wallet.Unlock(key)
	if err != nil {
		return err
	}
	return nil
}

// blankHostTester creates a host tester where the modules are created but no
// extra initialization has been done, for example no blocks have been mined
// and the wallet keys have not been created.
func blankHostTester(name string) (*hostTester, error) {
	testdir := build.TempDir(modules.HostDir, name)

	// Create the modules.
	g, err := gateway.New(":0", filepath.Join(testdir, modules.GatewayDir))
	if err != nil {
		return nil, err
	}
	cs, err := consensus.New(g, filepath.Join(testdir, modules.ConsensusDir))
	if err != nil {
		return nil, err
	}
	tp, err := transactionpool.New(cs, g)
	if err != nil {
		return nil, err
	}
	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, err
	}
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, err
	}
	h, err := New(cs, tp, w, ":0", filepath.Join(testdir, modules.HostDir))
	if err != nil {
		return nil, err
	}

	// Assemble all objects into a hostTester
	ht := &hostTester{
		cs:      cs,
		gateway: g,
		miner:   m,
		tpool:   tp,
		wallet:  w,

		host: h,

		persistDir: testdir,
	}

	return ht, nil
}

// newHostTester creates a host tester with an initialized wallet and money in
// that wallet.
func newHostTester(name string) (*hostTester, error) {
	// Create a blank host tester.
	ht, err := blankHostTester(name)
	if err != nil {
		return nil, err
	}

	// Initialize the wallet and mine blocks until the wallet has money.
	err = ht.initWallet()
	if err != nil {
		return nil, err
	}
	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
		_, err = ht.miner.AddBlock()
		if err != nil {
			return nil, err
		}
	}
	return ht, nil
}

// TestHostInitialization checks that the host intializes to sensisble default
// values.
func TestHostInitialization(t *testing.T) {
	// Create a blank host tester and check that the height is zero.
	bht, err := blankHostTester("TestHostInitialization")
	if err != nil {
		t.Fatal(err)
	}
	if bht.host.blockHeight != 0 {
		t.Error("host initialized to the wrong block height")
	}

	// Initialize the wallet so that a block can be mined, then mine a block
	// and check that it sets the host height to 1.
	err = bht.initWallet()
	if err != nil {
		t.Fatal(err)
	}
	_, err = bht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if bht.host.blockHeight != 1 {
		t.Fatal("block height did not increase correctly after first block mined")
	}
}

// TestStartupRescan probes the startupRescan function, verifying that it
// works in the naive case. The rescan is triggered manually.
func TestStartupRescan(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	ht, err := newHostTester("TestStartupRescan")
	if err != nil {
		t.Fatal(err)
	}

	// Check that the host's persistent variables have incorporated the first
	// few blocks.
	if ht.host.recentChange == (modules.ConsensusChangeID{}) || ht.host.blockHeight == 0 {
		t.Fatal("host variables do not indicate that the host is tracking the consensus set correctly")
	}
	oldChange := ht.host.recentChange
	oldHeight := ht.host.blockHeight

	// Corrupt the variables and perform a rescan to see if they reset
	// correctly.
	ht.host.recentChange[0]++
	ht.host.blockHeight += 100e3
	ht.cs.Unsubscribe(ht.host)
	err = ht.host.startupRescan()
	if err != nil {
		t.Fatal(err)
	}
	if oldChange != ht.host.recentChange || oldHeight != ht.host.blockHeight {
		t.Error("consensus tracking variables were not reset correctly after rescan")
	}
}

// TestIntegrationAutoRescan checks that a rescan is triggered during New if
// the consensus set becomes desynchronized.
func TestIntegrationAutoRescan(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	ht, err := newHostTester("TestIntegrationAutoRescan")
	if err != nil {
		t.Fatal(err)
	}

	// Check that the host's persistent variables have incorporated the first
	// few blocks.
	if ht.host.recentChange == (modules.ConsensusChangeID{}) || ht.host.blockHeight == 0 {
		t.Fatal("host variables do not indicate that the host is tracking the consensus set correctly")
	}
	oldChange := ht.host.recentChange
	oldHeight := ht.host.blockHeight

	// Corrupt the variables, then close the host.
	ht.host.recentChange[0]++
	ht.host.blockHeight += 100e3
	err = ht.host.Close() // host saves upon closing
	if err != nil {
		t.Fatal(err)
	}

	// Create a new host and check that the persist variables have correctly
	// reset.
	h, err := New(ht.cs, ht.tpool, ht.wallet, ":0", ht.persistDir)
	if err != nil {
		t.Fatal(err)
	}
	if oldChange != h.recentChange || oldHeight != h.blockHeight {
		t.Error("consensus tracking variables were not reset correctly after rescan")
	}
}
<|endoftext|>


<commit_before>package kite

import (
	"fmt"
	"sync/atomic"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/koding/kite/kitekey"
	"github.com/koding/kite/protocol"
)

const (
	renewBefore   = 30 * time.Second
	retryInterval = 10 * time.Second
)

// TokenRenewer renews the token of a Client just before it expires.
type TokenRenewer struct {
	client           *Client
	localKite        *Kite
	validUntil       time.Time
	signalRenewToken chan struct{}
	disconnect       chan struct{}
	active           uint32
}

func NewTokenRenewer(r *Client, k *Kite) (*TokenRenewer, error) {
	t := &TokenRenewer{
		client:           r,
		localKite:        k,
		signalRenewToken: make(chan struct{}, 1),
		disconnect:       make(chan struct{}, 1),
	}
	return t, t.parse(r.Auth.Key)
}

// parse the token string and set
func (t *TokenRenewer) parse(tokenString string) error {
	claims := &kitekey.KiteClaims{}

	_, err := jwt.ParseWithClaims(tokenString, claims, t.localKite.RSAKey)
	if err != nil {
		valErr, ok := err.(*jwt.ValidationError)
		if !ok {
			return err
		}

		// do noy return for ValidationErrorSignatureValid. This is because we
		// might asked for a kite who's public Key is different what we have.
		// We still should be able to send them requests.
		if (valErr.Errors & jwt.ValidationErrorSignatureInvalid) == 0 {
			return fmt.Errorf("Cannot parse token: %s", err)
		}
	}

	t.validUntil = time.Unix(claims.ExpiresAt, 0).UTC()
	return nil
}

// RenewWhenExpires renews the token before it expires.
func (t *TokenRenewer) RenewWhenExpires() {
	if atomic.CompareAndSwapUint32(&t.active, 0, 1) {
		t.client.OnConnect(t.startRenewLoop)
		t.client.OnTokenExpire(t.sendRenewTokenSignal)
		t.client.OnDisconnect(t.sendDisconnectSignal)
	}
}

func (t *TokenRenewer) renewLoop() {
	// renews token before it expires (sends the first signal to the goroutine below)
	go time.AfterFunc(t.renewDuration(), t.sendRenewTokenSignal)

	// renew token on signal util remote kite disconnects.
	for {
		select {
		case <-t.signalRenewToken:
			switch err := t.renewToken(); err {
			case nil:
				go time.AfterFunc(t.renewDuration(), t.sendRenewTokenSignal)
			case ErrNoKitesAvailable:
				// If kite went down we're not going to renew the token,
				// as we need to dial either way.
				//
				// This case handles a situation, when kite missed
				// disconnect signal (observed to happen with XHR transport).
				return
			default:
				t.localKite.Log.Error("token renewer: %s Cannot renew token for Kite: %s I will retry in %d seconds...",
					err, t.client.ID, retryInterval/time.Second)
				// Need to sleep here litle bit because a signal is sent
				// when an expired token is detected on incoming request.
				// This sleep prevents the signal from coming too fast.
				time.Sleep(1 * time.Second)
				go time.AfterFunc(retryInterval, t.sendRenewTokenSignal)
			}
		case <-t.disconnect:
			return
		}
	}
}

// The duration from now to the time token needs to be renewed.
// Needs to be calculated after renewing the token.
func (t *TokenRenewer) renewDuration() time.Duration {
	return t.validUntil.Add(-renewBefore).Sub(time.Now().UTC())
}

func (t *TokenRenewer) startRenewLoop() {
	go t.renewLoop()
}

func (t *TokenRenewer) sendRenewTokenSignal() {
	// Needs to be non-blocking because tokenRenewer may be stopped.
	select {
	case t.signalRenewToken <- struct{}{}:
	default:
	}
}

func (t *TokenRenewer) sendDisconnectSignal() {
	// Needs to be non-blocking because tokenRenewer may be stopped.
	select {
	case t.disconnect <- struct{}{}:
	default:
	}
}

// renewToken gets a new token from a kontrolClient, parses it and sets it as the token.
func (t *TokenRenewer) renewToken() error {
	renew := &protocol.Kite{
		ID: t.client.Kite.ID,
	}

	token, err := t.localKite.GetToken(renew)
	if err != nil {
		return err
	}

	if err = t.parse(token); err != nil {
		return err
	}

	t.client.authMu.Lock()
	t.client.Auth.Key = token
	t.client.authMu.Unlock()

	t.client.callOnTokenRenewHandlers(token)

	return nil
}
<commit_msg>tokenrenewer: improve fix for a panic #187<commit_after>package kite

import (
	"fmt"
	"strings"
	"sync"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/koding/kite/kitekey"
	"github.com/koding/kite/protocol"
)

const (
	renewBefore   = 30 * time.Second
	retryInterval = 10 * time.Second
)

// TokenRenewer renews the token of a Client just before it expires.
type TokenRenewer struct {
	client           *Client
	localKite        *Kite
	validUntil       time.Time
	signalRenewToken chan struct{}
	disconnect       chan struct{}
	once             sync.Once // for c.installHandlers
	renewLoopWG      sync.WaitGroup
}

func NewTokenRenewer(r *Client, k *Kite) (*TokenRenewer, error) {
	t := &TokenRenewer{
		client:           r,
		localKite:        k,
		signalRenewToken: make(chan struct{}, 1),
		disconnect:       make(chan struct{}, 1),
	}
	return t, t.parse(r.Auth.Key)
}

// parse the token string and set
func (t *TokenRenewer) parse(tokenString string) error {
	claims := &kitekey.KiteClaims{}

	_, err := jwt.ParseWithClaims(tokenString, claims, t.localKite.RSAKey)
	if err != nil {
		valErr, ok := err.(*jwt.ValidationError)
		if !ok {
			return err
		}

		// do noy return for ValidationErrorSignatureValid. This is because we
		// might asked for a kite who's public Key is different what we have.
		// We still should be able to send them requests.
		if (valErr.Errors & jwt.ValidationErrorSignatureInvalid) == 0 {
			return fmt.Errorf("Cannot parse token: %s", err)
		}
	}

	t.validUntil = time.Unix(claims.ExpiresAt, 0).UTC()
	return nil
}

// RenewWhenExpires renews the token before it expires.
func (t *TokenRenewer) RenewWhenExpires() {
	t.once.Do(t.installHandlers)
}

func (t *TokenRenewer) installHandlers() {
	t.client.OnConnect(t.startRenewLoop)
	t.client.OnTokenExpire(t.sendRenewTokenSignal)
	t.client.OnDisconnect(t.sendDisconnectSignal)
}

func (t *TokenRenewer) renewLoop() {
	t.renewLoopWG.Add(1)
	defer t.renewLoopWG.Done()

	// renews token before it expires (sends the first signal to the goroutine below)
	go time.AfterFunc(t.renewDuration(), t.sendRenewTokenSignal)

	// renew token on signal util remote kite disconnects.
	for {
		select {
		case <-t.signalRenewToken:
			switch err := t.renewToken(); {
			case err == nil:
				go time.AfterFunc(t.renewDuration(), t.sendRenewTokenSignal)
			case err == ErrNoKitesAvailable || strings.Contains(err.Error(), "no kites found"):
				// If kite went down we're not going to renew the token,
				// as we need to dial either way.
				//
				// This case handles a situation, when kite missed
				// disconnect signal (observed to happen with XHR transport).
			default:
				t.localKite.Log.Error("token renewer: %s Cannot renew token for Kite: %s I will retry in %d seconds...",
					err, t.client.ID, retryInterval/time.Second)
				// Need to sleep here litle bit because a signal is sent
				// when an expired token is detected on incoming request.
				// This sleep prevents the signal from coming too fast.
				time.Sleep(1 * time.Second)
				go time.AfterFunc(retryInterval, t.sendRenewTokenSignal)
			}
		case <-t.disconnect:
			return
		}
	}
}

// The duration from now to the time token needs to be renewed.
// Needs to be calculated after renewing the token.
func (t *TokenRenewer) renewDuration() time.Duration {
	return t.validUntil.Add(-renewBefore).Sub(time.Now().UTC())
}

func (t *TokenRenewer) startRenewLoop() {
	// In case when t.client missed a disconnect signal (e.g. due to timeout observed
	// by the remote end), previous renewLoop will be still running.
	t.sendDisconnectSignal()

	// if we don't wait to observe previous renewLoop goroutine handle the disconnect
	// signal, we'd have a race resulting in new renewLoop goroutine handling it.
	t.renewLoopWG.Wait()

	go t.renewLoop()
}

func (t *TokenRenewer) sendRenewTokenSignal() {
	// Needs to be non-blocking because tokenRenewer may be stopped.
	select {
	case t.signalRenewToken <- struct{}{}:
	default:
	}
}

func (t *TokenRenewer) sendDisconnectSignal() {
	// Needs to be non-blocking because tokenRenewer may be stopped.
	select {
	case t.disconnect <- struct{}{}:
	default:
	}
}

// renewToken gets a new token from a kontrolClient, parses it and sets it as the token.
func (t *TokenRenewer) renewToken() error {
	renew := &protocol.Kite{
		ID: t.client.Kite.ID,
	}

	token, err := t.localKite.GetToken(renew)
	if err != nil {
		return err
	}

	if err = t.parse(token); err != nil {
		return err
	}

	t.client.authMu.Lock()
	t.client.Auth.Key = token
	t.client.authMu.Unlock()

	t.client.callOnTokenRenewHandlers(token)

	return nil
}
<|endoftext|>


<commit_before>package nameserver

import (
	"github.com/miekg/dns"
	. "github.com/zettio/weave/common"
	"net"
)

type MDNSServer struct {
	localAddrs []net.Addr
	sendconn   *net.UDPConn
	zone       Zone
}

func NewMDNSServer(zone Zone) (*MDNSServer, error) {
	// This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work
	sendconn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if err != nil {
		return nil, err
	}
	return &MDNSServer{sendconn: sendconn, zone: zone}, nil
}

// Return true if testaddr is a UDP address with IP matching my local i/f
func (s *MDNSServer) addrIsLocal(testaddr net.Addr) bool {
	if udpaddr, ok := testaddr.(*net.UDPAddr); ok {
		for _, localaddr := range s.localAddrs {
			if ipnetlocal, ok := localaddr.(*net.IPNet); ok {
				if ipnetlocal.IP.Equal(udpaddr.IP) {
					return true
				}
			}
		}
	}
	return false
}

func (s *MDNSServer) Start(ifi *net.Interface) error {
	conn, err := LinkLocalMulticastListener(ifi)
	if err != nil {
		return err
	}

	if ifi == nil {
		s.localAddrs, err = net.InterfaceAddrs()
	} else {
		s.localAddrs, err = ifi.Addrs()
	}
	if err != nil {
		return err
	}

	handler := func(qtype uint16, lookup func(*dns.Msg, *dns.Question) *dns.Msg) dns.HandlerFunc {
		return func(w dns.ResponseWriter, r *dns.Msg) {
			// Handle only questions, ignore answers. We might also
			// ignore questions that arise locally (i.e., that come
			// from an IP we think is local), but in the interest of
			// avoiding complication, and easier testing, this is
			// elided on the assumption that the client wouldn't ask
			// if it already knew the answer, and if it does ask,
			// it'll be happy to get an answer.
			if len(r.Answer) == 0 && len(r.Question) > 0 {
				q := &r.Question[0]
				if q.Qtype == qtype {
					if m := lookup(r, q); m != nil {
						Debug.Printf("Found local answer to mDNS query %s", q.Name)
						if err = s.sendResponse(m); err != nil {
							Warning.Printf("Error writing to %s", w)
						}
					} else {
						Debug.Printf("No local answer for mDNS query %s", q.Name)
					}
				}
			}
		}
	}

	handleLocal := handler(dns.TypeA, func(r *dns.Msg, q *dns.Question) *dns.Msg {
		if ip, err := s.zone.LookupLocal(q.Name); err == nil {
			return makeAddressReply(r, q, []net.IP{ip})
		} else {
			return nil
		}
	})

	handleReverse := handler(dns.TypePTR, func(r *dns.Msg, q *dns.Question) *dns.Msg {
		if name, err := s.zone.ReverseLookupLocal(q.Name); err == nil {
			return makePTRReply(r, q, []string{name})
		} else {
			return nil
		}
	})

	mux := dns.NewServeMux()
	mux.HandleFunc(LOCAL_DOMAIN, handleLocal)
	mux.HandleFunc(RDNS_DOMAIN, handleReverse)

	go dns.ActivateAndServe(nil, conn, mux)
	return err
}

func (s *MDNSServer) sendResponse(m *dns.Msg) error {
	buf, err := m.Pack()
	if err != nil {
		return err
	}
	_, err = s.sendconn.WriteTo(buf, ipv4Addr)
	return err
}
<commit_msg>Factor the making of handlers out<commit_after>package nameserver

import (
	"github.com/miekg/dns"
	. "github.com/zettio/weave/common"
	"net"
)

type MDNSServer struct {
	localAddrs []net.Addr
	sendconn   *net.UDPConn
	zone       Zone
}

func NewMDNSServer(zone Zone) (*MDNSServer, error) {
	// This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work
	sendconn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if err != nil {
		return nil, err
	}
	return &MDNSServer{sendconn: sendconn, zone: zone}, nil
}

// Return true if testaddr is a UDP address with IP matching my local i/f
func (s *MDNSServer) addrIsLocal(testaddr net.Addr) bool {
	if udpaddr, ok := testaddr.(*net.UDPAddr); ok {
		for _, localaddr := range s.localAddrs {
			if ipnetlocal, ok := localaddr.(*net.IPNet); ok {
				if ipnetlocal.IP.Equal(udpaddr.IP) {
					return true
				}
			}
		}
	}
	return false
}

func (s *MDNSServer) Start(ifi *net.Interface) error {
	conn, err := LinkLocalMulticastListener(ifi)
	if err != nil {
		return err
	}

	if ifi == nil {
		s.localAddrs, err = net.InterfaceAddrs()
	} else {
		s.localAddrs, err = ifi.Addrs()
	}
	if err != nil {
		return err
	}

	handleLocal := s.makeHandler(dns.TypeA,
		func(zone Lookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if ip, err := zone.LookupLocal(q.Name); err == nil {
				return makeAddressReply(r, q, []net.IP{ip})
			} else {
				return nil
			}
		})

	handleReverse := s.makeHandler(dns.TypePTR,
		func(zone Lookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if name, err := zone.ReverseLookupLocal(q.Name); err == nil {
				return makePTRReply(r, q, []string{name})
			} else {
				return nil
			}
		})

	mux := dns.NewServeMux()
	mux.HandleFunc(LOCAL_DOMAIN, handleLocal)
	mux.HandleFunc(RDNS_DOMAIN, handleReverse)

	go dns.ActivateAndServe(nil, conn, mux)
	return err
}

type LookupFunc func(Lookup, *dns.Msg, *dns.Question) *dns.Msg

func (s *MDNSServer) makeHandler(qtype uint16, lookup LookupFunc) dns.HandlerFunc {
	return func(_ dns.ResponseWriter, r *dns.Msg) {
		// Handle only questions, ignore answers. We might also ignore
		// questions that arise locally (i.e., that come from an IP we
		// think is local), but in the interest of avoiding
		// complication, and easier testing, this is elided on the
		// assumption that the client wouldn't ask if it already knew
		// the answer, and if it does ask, it'll be happy to get an
		// answer.
		if len(r.Answer) == 0 && len(r.Question) > 0 {
			q := &r.Question[0]
			if q.Qtype == qtype {
				if m := lookup(s.zone, r, q); m != nil {
					Debug.Printf("Found local answer to mDNS query %s", q.Name)
					if err := s.sendResponse(m); err != nil {
						Warning.Printf("Error writing to %s", s.sendconn)
					}
				} else {
					Debug.Printf("No local answer for mDNS query %s", q.Name)
				}
			}
		}
	}
}

func (s *MDNSServer) sendResponse(m *dns.Msg) error {
	buf, err := m.Pack()
	if err != nil {
		return err
	}
	_, err = s.sendconn.WriteTo(buf, ipv4Addr)
	return err
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package newtutil

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"

	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/util"
)

var NewtVersion = Version{1, 5, 9900}
var NewtVersionStr = "1.6.0-dev"
var NewtGitHash = "unknown"
var NewtDate = "unknown"

var NewtBlinkyTag string = "master"
var NewtNumJobs int
var NewtForce bool
var NewtAsk bool

const CORE_REPO_NAME string = "apache-mynewt-core"
const ARDUINO_ZERO_REPO_NAME string = "mynewt_arduino_zero"

type Version struct {
	Major    int64
	Minor    int64
	Revision int64
}

func ParseVersion(s string) (Version, error) {
	v := Version{}
	parseErr := util.FmtNewtError("Invalid version string: %s", s)

	parts := strings.Split(s, ".")
	if len(parts) != 3 {
		return v, parseErr
	}

	var err error

	v.Major, err = strconv.ParseInt(parts[0], 10, 64)
	if err != nil {
		return v, parseErr
	}

	v.Minor, err = strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return v, parseErr
	}

	v.Revision, err = strconv.ParseInt(parts[2], 10, 64)
	if err != nil {
		return v, parseErr
	}

	return v, nil
}

func (v *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Revision)
}

func VerCmp(v1 Version, v2 Version) int64 {
	if r := v1.Major - v2.Major; r != 0 {
		return r
	}

	if r := v1.Minor - v2.Minor; r != 0 {
		return r
	}

	if r := v1.Revision - v2.Revision; r != 0 {
		return r
	}

	return 0
}

// Parses a string of the following form:
//     [@repo]<path/to/package>
//
// @return string               repo name ("" if no repo)
//         string               package name
//         error                if invalid package string
func ParsePackageString(pkgStr string) (string, string, error) {
	// remove possible trailing '/'
	pkgStr = strings.TrimSuffix(pkgStr, "/")

	if strings.HasPrefix(pkgStr, "@") {
		nameParts := strings.SplitN(pkgStr[1:], "/", 2)
		if len(nameParts) == 1 {
			return "", "", util.NewNewtError(fmt.Sprintf("Invalid package "+
				"string; contains repo but no package name: %s", pkgStr))
		} else {
			return nameParts[0], nameParts[1], nil
		}
	} else {
		return "", pkgStr, nil
	}
}

func FindRepoDesignator(s string) (int, int) {
	start := strings.Index(s, "@")
	if start == -1 {
		return -1, -1
	}

	len := strings.Index(s[start:], "/")
	if len == -1 {
		return -1, -1
	}

	return start, len
}

func ReplaceRepoDesignators(s string) (string, bool) {
	start, len := FindRepoDesignator(s)
	if start == -1 {
		return s, false
	}
	repoName := s[start+1 : start+len]

	proj := interfaces.GetProject()
	repoPath := proj.FindRepoPath(repoName)
	if repoPath == "" {
		return s, false
	}

	// Trim common project base from repo path.
	relRepoPath := strings.TrimPrefix(repoPath, proj.Path()+"/")

	return s[:start] + relRepoPath + s[start+len:], true
}

func BuildPackageString(repoName string, pkgName string) string {
	if repoName != "" {
		return "@" + repoName + "/" + pkgName
	} else {
		return pkgName
	}
}

func GeneratedPreamble() string {
	return fmt.Sprintf(
		"/**\n * This file was generated by Apache newt version: %s\n */\n\n",
		NewtVersionStr)
}

// Creates a temporary directory for downloading a repo.
func MakeTempRepoDir() (string, error) {
	tmpdir, err := ioutil.TempDir("", "newt-repo")
	if err != nil {
		return "", util.ChildNewtError(err)
	}

	return tmpdir, nil
}

func ProjRelPath(path string) string {
	if strings.HasPrefix(path, "/") {
		return path
	}

	proj := interfaces.GetProject()
	return strings.TrimPrefix(path, proj.Path()+"/")
}
<commit_msg>Bump version to 1.7.0-dev<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package newtutil

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"

	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/util"
)

var NewtVersion = Version{1, 6, 9900}
var NewtVersionStr = "1.7.0-dev"
var NewtGitHash = "unknown"
var NewtDate = "unknown"

var NewtBlinkyTag string = "master"
var NewtNumJobs int
var NewtForce bool
var NewtAsk bool

const CORE_REPO_NAME string = "apache-mynewt-core"
const ARDUINO_ZERO_REPO_NAME string = "mynewt_arduino_zero"

type Version struct {
	Major    int64
	Minor    int64
	Revision int64
}

func ParseVersion(s string) (Version, error) {
	v := Version{}
	parseErr := util.FmtNewtError("Invalid version string: %s", s)

	parts := strings.Split(s, ".")
	if len(parts) != 3 {
		return v, parseErr
	}

	var err error

	v.Major, err = strconv.ParseInt(parts[0], 10, 64)
	if err != nil {
		return v, parseErr
	}

	v.Minor, err = strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return v, parseErr
	}

	v.Revision, err = strconv.ParseInt(parts[2], 10, 64)
	if err != nil {
		return v, parseErr
	}

	return v, nil
}

func (v *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Revision)
}

func VerCmp(v1 Version, v2 Version) int64 {
	if r := v1.Major - v2.Major; r != 0 {
		return r
	}

	if r := v1.Minor - v2.Minor; r != 0 {
		return r
	}

	if r := v1.Revision - v2.Revision; r != 0 {
		return r
	}

	return 0
}

// Parses a string of the following form:
//     [@repo]<path/to/package>
//
// @return string               repo name ("" if no repo)
//         string               package name
//         error                if invalid package string
func ParsePackageString(pkgStr string) (string, string, error) {
	// remove possible trailing '/'
	pkgStr = strings.TrimSuffix(pkgStr, "/")

	if strings.HasPrefix(pkgStr, "@") {
		nameParts := strings.SplitN(pkgStr[1:], "/", 2)
		if len(nameParts) == 1 {
			return "", "", util.NewNewtError(fmt.Sprintf("Invalid package "+
				"string; contains repo but no package name: %s", pkgStr))
		} else {
			return nameParts[0], nameParts[1], nil
		}
	} else {
		return "", pkgStr, nil
	}
}

func FindRepoDesignator(s string) (int, int) {
	start := strings.Index(s, "@")
	if start == -1 {
		return -1, -1
	}

	len := strings.Index(s[start:], "/")
	if len == -1 {
		return -1, -1
	}

	return start, len
}

func ReplaceRepoDesignators(s string) (string, bool) {
	start, len := FindRepoDesignator(s)
	if start == -1 {
		return s, false
	}
	repoName := s[start+1 : start+len]

	proj := interfaces.GetProject()
	repoPath := proj.FindRepoPath(repoName)
	if repoPath == "" {
		return s, false
	}

	// Trim common project base from repo path.
	relRepoPath := strings.TrimPrefix(repoPath, proj.Path()+"/")

	return s[:start] + relRepoPath + s[start+len:], true
}

func BuildPackageString(repoName string, pkgName string) string {
	if repoName != "" {
		return "@" + repoName + "/" + pkgName
	} else {
		return pkgName
	}
}

func GeneratedPreamble() string {
	return fmt.Sprintf(
		"/**\n * This file was generated by Apache newt version: %s\n */\n\n",
		NewtVersionStr)
}

// Creates a temporary directory for downloading a repo.
func MakeTempRepoDir() (string, error) {
	tmpdir, err := ioutil.TempDir("", "newt-repo")
	if err != nil {
		return "", util.ChildNewtError(err)
	}

	return tmpdir, nil
}

func ProjRelPath(path string) string {
	if strings.HasPrefix(path, "/") {
		return path
	}

	proj := interfaces.GetProject()
	return strings.TrimPrefix(path, proj.Path()+"/")
}
<|endoftext|>


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

// WARNING: tricky code just for testing purposes, do not use as example.

package main

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

var vbuf, buf string

func quit(g *gocui.Gui, v *gocui.View) error {
	vbuf = v.ViewBuffer()
	buf = v.Buffer()
	return gocui.ErrQuit
}

func overwrite(g *gocui.Gui, v *gocui.View) error {
	v.Overwrite = !v.Overwrite
	return nil
}

func layout(g *gocui.Gui) error {
	_, maxY := g.Size()
	if v, err := g.SetView("main", 0, 0, 20, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Editable = true
		v.Wrap = true
		if _, err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}

	g.Cursor = true
	g.Mouse = true

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("main", gocui.KeyCtrlI, gocui.ModNone, overwrite); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}

	g.Close()

	fmt.Printf("VBUF:\n%s\n", vbuf)
	fmt.Printf("BUF:\n%s\n", buf)
}
<commit_msg>Fix warning in _examples/bufs.go<commit_after>// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// WARNING: tricky code just for testing purposes, do not use as reference.

package main

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

var vbuf, buf string

func quit(g *gocui.Gui, v *gocui.View) error {
	vbuf = v.ViewBuffer()
	buf = v.Buffer()
	return gocui.ErrQuit
}

func overwrite(g *gocui.Gui, v *gocui.View) error {
	v.Overwrite = !v.Overwrite
	return nil
}

func layout(g *gocui.Gui) error {
	_, maxY := g.Size()
	if v, err := g.SetView("main", 0, 0, 20, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Editable = true
		v.Wrap = true
		if _, err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}

	g.Cursor = true
	g.Mouse = true

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("main", gocui.KeyCtrlI, gocui.ModNone, overwrite); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}

	g.Close()

	fmt.Printf("VBUF:\n%s\n", vbuf)
	fmt.Printf("BUF:\n%s\n", buf)
}
<|endoftext|>


<commit_before>// Copyright 2014 The gocui 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 main

import (
	"fmt"
	"log"
	"strings"

	"github.com/jroimartin/gocui"
)

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("main", 1, 1, maxX-1, maxY-1); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		v.Wrap = true
		v.WrapPrefix = "> "

		line := strings.Repeat("This is a long line -- ", 10)
		fmt.Fprintf(v, "%v\n\n", line)
		fmt.Fprint(v, "Short")
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrorQuit
}

func main() {
	var err error

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetLayout(layout)
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	err = g.MainLoop()
	if err != nil && err != gocui.ErrorQuit {
		log.Panicln(err)
	}
}
<commit_msg>_examples/wrap: Minor changes<commit_after>// Copyright 2014 The gocui 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 main

import (
	"fmt"
	"log"
	"strings"

	"github.com/jroimartin/gocui"
)

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("main", 1, 1, maxX-1, maxY-1); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		v.Wrap = true
		v.WrapPrefix = "> "

		line := strings.Repeat("This is a long line -- ", 10)
		fmt.Fprintf(v, "%s\n\n", line)
		fmt.Fprintln(v, "Short")
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrorQuit
}

func main() {
	var err error

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetLayout(layout)
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	err = g.MainLoop()
	if err != nil && err != gocui.ErrorQuit {
		log.Panicln(err)
	}
}
<|endoftext|>


<commit_before>/*
    DNS-over-HTTPS
    Copyright (C) 2017 Star Brilliant <m13253@hotmail.com>

    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 main

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"time"
	"github.com/miekg/dns"
	"../json-dns"
)

type Client struct {
	addr			string
	upstream		string
	bootstraps		[]string
	timeout			uint
	noECS			bool
	verbose			bool
	udpServer		*dns.Server
	tcpServer		*dns.Server
	httpClient		*http.Client
}

func NewClient(addr, upstream string, bootstraps []string, timeout uint, noECS, verbose bool) (c *Client, err error) {
	c = &Client {
		addr: addr,
		upstream: upstream,
		bootstraps: bootstraps,
		timeout: timeout,
		noECS: noECS,
		verbose: verbose,
	}
	c.udpServer = &dns.Server {
		Addr: addr,
		Net: "udp",
		Handler: dns.HandlerFunc(c.udpHandlerFunc),
		UDPSize: 4096,
	}
	c.tcpServer = &dns.Server {
		Addr: addr,
		Net: "tcp",
		Handler: dns.HandlerFunc(c.tcpHandlerFunc),
	}
	bootResolver := net.DefaultResolver
	if len(c.bootstraps) != 0 {
		for i, bootstrap := range c.bootstraps {
			bootstrapAddr, err := net.ResolveUDPAddr("udp", bootstrap)
			if err != nil {
				bootstrapAddr, err = net.ResolveUDPAddr("udp", "[" + bootstrap + "]:53")
			}
			if err != nil { return nil, err }
			c.bootstraps[i] = bootstrapAddr.String()
		}
		bootResolver = &net.Resolver {
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				var d net.Dialer
				num_servers := len(c.bootstraps)
				bootstrap := c.bootstraps[rand.Intn(num_servers)]
				conn, err := d.DialContext(ctx, network, bootstrap)
				return conn, err
			},
		}
	}
	httpTransport := *http.DefaultTransport.(*http.Transport)
	httpTransport.DialContext = (&net.Dialer {
		Timeout: time.Duration(c.timeout) * time.Second,
		KeepAlive: 30 * time.Second,
		DualStack: true,
		Resolver: bootResolver,
	}).DialContext
	cookieJar, err := cookiejar.New(nil)
	if err != nil { return nil, err }
	c.httpClient = &http.Client {
		Transport: &httpTransport,
		Jar: cookieJar,
	}
	return c, nil
}

func (c *Client) Start() error {
	result := make(chan error)
	go func() {
		err := c.udpServer.ListenAndServe()
		if err != nil {
			log.Println(err)
		}
		result <- err
	} ()
	go func() {
		err := c.tcpServer.ListenAndServe()
		if err != nil {
			log.Println(err)
		}
		result <- err
	} ()
	err := <-result
	if err != nil {
		return err
	}
	err = <-result
	return err
}

func (c *Client) handlerFunc(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
	if r.Response == true {
		log.Println("Received a response packet")
		return
	}

	reply := jsonDNS.PrepareReply(r)

	if len(r.Question) != 1 {
		log.Println("Number of questions is not 1")
		reply.Rcode = dns.RcodeFormatError
		w.WriteMsg(reply)
		return
	}
	question := r.Question[0]
	questionName := strings.ToLower(question.Name)
	questionType := ""
	if qtype, ok := dns.TypeToString[question.Qtype]; ok {
		questionType = qtype
	} else {
		questionType = strconv.Itoa(int(question.Qtype))
	}

	if c.verbose{
		fmt.Printf("%s - - [%s] \"%s IN %s\"\n", w.RemoteAddr(), time.Now().Format("02/Jan/2006:15:04:05 -0700"), questionName, questionType)
	}

	requestURL := fmt.Sprintf("%s?name=%s&type=%s", c.upstream, url.QueryEscape(questionName), url.QueryEscape(questionType))

	if r.CheckingDisabled {
		requestURL += "&cd=1"
	}

	udpSize := uint16(512)
	if opt := r.IsEdns0(); opt != nil {
		udpSize = opt.UDPSize()
	}

	ednsClientAddress, ednsClientNetmask := c.findClientIP(w, r)
	if ednsClientAddress != nil {
		requestURL += fmt.Sprintf("&edns_client_subnet=%s/%d", ednsClientAddress.String(), ednsClientNetmask)
	}

	req, err := http.NewRequest("GET", requestURL, nil)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	req.Header.Set("User-Agent", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
	resp, err := c.httpClient.Do(req)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	if resp.StatusCode != 200 {
		log.Printf("Server returned error: %s\n", resp.Status)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	var respJson jsonDNS.Response
	err = json.Unmarshal(body, &respJson)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	fullReply := jsonDNS.Unmarshal(reply, &respJson, udpSize, ednsClientNetmask)
	buf, err := fullReply.Pack()
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	if !isTCP && len(buf) > int(udpSize) {
		fullReply.Truncated = true
		buf, err = fullReply.Pack()
		if err != nil {
			log.Println(err)
			return
		}
		buf = buf[:udpSize]
	}
	w.Write(buf)
}

func (c *Client) udpHandlerFunc(w dns.ResponseWriter, r *dns.Msg) {
	c.handlerFunc(w, r, false)
}

func (c *Client) tcpHandlerFunc(w dns.ResponseWriter, r *dns.Msg) {
	c.handlerFunc(w, r, true)
}

var (
	ipv4Mask24	net.IPMask = net.IPMask { 255, 255, 255, 0 }
	ipv6Mask48	net.IPMask = net.CIDRMask(48, 128)
)

func (c *Client) findClientIP(w dns.ResponseWriter, r *dns.Msg) (ednsClientAddress net.IP, ednsClientNetmask uint8) {
	ednsClientNetmask = 255
	if c.noECS {
		return net.IPv4(0, 0, 0, 0), 0
	}
	if opt := r.IsEdns0(); opt != nil {
		for _, option := range opt.Option {
			if option.Option() == dns.EDNS0SUBNET {
				edns0Subnet := option.(*dns.EDNS0_SUBNET)
				ednsClientAddress = edns0Subnet.Address
				ednsClientNetmask = edns0Subnet.SourceNetmask
				return
			}
		}
	}
	remoteAddr, err := net.ResolveUDPAddr("udp", w.RemoteAddr().String())
	if err != nil {
		return
	}
	if ip := remoteAddr.IP; jsonDNS.IsGlobalIP(ip) {
		if ipv4 := ip.To4(); ipv4 != nil {
			ednsClientAddress = ipv4.Mask(ipv4Mask24)
			ednsClientNetmask = 24
		} else {
			ednsClientAddress = ip.Mask(ipv6Mask48)
			ednsClientNetmask = 48
		}
	}
	return
}
<commit_msg>Enable Cookie, which might have better CDN cache performance<commit_after>/*
    DNS-over-HTTPS
    Copyright (C) 2017 Star Brilliant <m13253@hotmail.com>

    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 main

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"time"
	"github.com/miekg/dns"
	"../json-dns"
)

type Client struct {
	addr			string
	upstream		string
	bootstraps		[]string
	timeout			uint
	noECS			bool
	verbose			bool
	udpServer		*dns.Server
	tcpServer		*dns.Server
	httpClient		*http.Client
}

func NewClient(addr, upstream string, bootstraps []string, timeout uint, noECS, verbose bool) (c *Client, err error) {
	c = &Client {
		addr: addr,
		upstream: upstream,
		bootstraps: bootstraps,
		timeout: timeout,
		noECS: noECS,
		verbose: verbose,
	}
	c.udpServer = &dns.Server {
		Addr: addr,
		Net: "udp",
		Handler: dns.HandlerFunc(c.udpHandlerFunc),
		UDPSize: 4096,
	}
	c.tcpServer = &dns.Server {
		Addr: addr,
		Net: "tcp",
		Handler: dns.HandlerFunc(c.tcpHandlerFunc),
	}
	bootResolver := net.DefaultResolver
	if len(c.bootstraps) != 0 {
		for i, bootstrap := range c.bootstraps {
			bootstrapAddr, err := net.ResolveUDPAddr("udp", bootstrap)
			if err != nil {
				bootstrapAddr, err = net.ResolveUDPAddr("udp", "[" + bootstrap + "]:53")
			}
			if err != nil { return nil, err }
			c.bootstraps[i] = bootstrapAddr.String()
		}
		bootResolver = &net.Resolver {
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				var d net.Dialer
				num_servers := len(c.bootstraps)
				bootstrap := c.bootstraps[rand.Intn(num_servers)]
				conn, err := d.DialContext(ctx, network, bootstrap)
				return conn, err
			},
		}
	}
	httpTransport := *http.DefaultTransport.(*http.Transport)
	httpTransport.DialContext = (&net.Dialer {
		Timeout: time.Duration(c.timeout) * time.Second,
		KeepAlive: 30 * time.Second,
		DualStack: true,
		Resolver: bootResolver,
	}).DialContext
	// Most CDNs require Cookie support to prevent DDoS attack
	cookieJar, err := cookiejar.New(nil)
	if err != nil { return nil, err }
	c.httpClient = &http.Client {
		Transport: &httpTransport,
		Jar: cookieJar,
	}
	return c, nil
}

func (c *Client) Start() error {
	result := make(chan error)
	go func() {
		err := c.udpServer.ListenAndServe()
		if err != nil {
			log.Println(err)
		}
		result <- err
	} ()
	go func() {
		err := c.tcpServer.ListenAndServe()
		if err != nil {
			log.Println(err)
		}
		result <- err
	} ()
	err := <-result
	if err != nil {
		return err
	}
	err = <-result
	return err
}

func (c *Client) handlerFunc(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
	if r.Response == true {
		log.Println("Received a response packet")
		return
	}

	reply := jsonDNS.PrepareReply(r)

	if len(r.Question) != 1 {
		log.Println("Number of questions is not 1")
		reply.Rcode = dns.RcodeFormatError
		w.WriteMsg(reply)
		return
	}
	question := r.Question[0]
	questionName := strings.ToLower(question.Name)
	questionType := ""
	if qtype, ok := dns.TypeToString[question.Qtype]; ok {
		questionType = qtype
	} else {
		questionType = strconv.Itoa(int(question.Qtype))
	}

	if c.verbose{
		fmt.Printf("%s - - [%s] \"%s IN %s\"\n", w.RemoteAddr(), time.Now().Format("02/Jan/2006:15:04:05 -0700"), questionName, questionType)
	}

	requestURL := fmt.Sprintf("%s?name=%s&type=%s", c.upstream, url.QueryEscape(questionName), url.QueryEscape(questionType))

	if r.CheckingDisabled {
		requestURL += "&cd=1"
	}

	udpSize := uint16(512)
	if opt := r.IsEdns0(); opt != nil {
		udpSize = opt.UDPSize()
	}

	ednsClientAddress, ednsClientNetmask := c.findClientIP(w, r)
	if ednsClientAddress != nil {
		requestURL += fmt.Sprintf("&edns_client_subnet=%s/%d", ednsClientAddress.String(), ednsClientNetmask)
	}

	req, err := http.NewRequest("GET", requestURL, nil)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	req.Header.Set("User-Agent", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
	resp, err := c.httpClient.Do(req)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	if resp.StatusCode != 200 {
		log.Printf("Server returned error: %s\n", resp.Status)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	var respJson jsonDNS.Response
	err = json.Unmarshal(body, &respJson)
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}

	fullReply := jsonDNS.Unmarshal(reply, &respJson, udpSize, ednsClientNetmask)
	buf, err := fullReply.Pack()
	if err != nil {
		log.Println(err)
		reply.Rcode = dns.RcodeServerFailure
		w.WriteMsg(reply)
		return
	}
	if !isTCP && len(buf) > int(udpSize) {
		fullReply.Truncated = true
		buf, err = fullReply.Pack()
		if err != nil {
			log.Println(err)
			return
		}
		buf = buf[:udpSize]
	}
	w.Write(buf)
}

func (c *Client) udpHandlerFunc(w dns.ResponseWriter, r *dns.Msg) {
	c.handlerFunc(w, r, false)
}

func (c *Client) tcpHandlerFunc(w dns.ResponseWriter, r *dns.Msg) {
	c.handlerFunc(w, r, true)
}

var (
	ipv4Mask24	net.IPMask = net.IPMask { 255, 255, 255, 0 }
	ipv6Mask48	net.IPMask = net.CIDRMask(48, 128)
)

func (c *Client) findClientIP(w dns.ResponseWriter, r *dns.Msg) (ednsClientAddress net.IP, ednsClientNetmask uint8) {
	ednsClientNetmask = 255
	if c.noECS {
		return net.IPv4(0, 0, 0, 0), 0
	}
	if opt := r.IsEdns0(); opt != nil {
		for _, option := range opt.Option {
			if option.Option() == dns.EDNS0SUBNET {
				edns0Subnet := option.(*dns.EDNS0_SUBNET)
				ednsClientAddress = edns0Subnet.Address
				ednsClientNetmask = edns0Subnet.SourceNetmask
				return
			}
		}
	}
	remoteAddr, err := net.ResolveUDPAddr("udp", w.RemoteAddr().String())
	if err != nil {
		return
	}
	if ip := remoteAddr.IP; jsonDNS.IsGlobalIP(ip) {
		if ipv4 := ip.To4(); ipv4 != nil {
			ednsClientAddress = ipv4.Mask(ipv4Mask24)
			ednsClientNetmask = 24
		} else {
			ednsClientAddress = ip.Mask(ipv6Mask48)
			ednsClientNetmask = 48
		}
	}
	return
}
<|endoftext|>