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

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

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

package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/juju/ratelimit"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/youtube/v3"
)

var (
	filename     = flag.String("filename", "", "Filename to upload. Can be a URL")
	title        = flag.String("title", "Test Title", "Video title")
	description  = flag.String("description", "Test Description", "Video description")
	category     = flag.String("category", "22", "Video category")
	keywords     = flag.String("keywords", "", "Comma separated list of video keywords")
	privacy      = flag.String("privacy", "private", "Video privacy status")
	showProgress = flag.Bool("progress", true, "Show progress indicator")
	rate         = flag.Int("ratelimit", 0, "Rate limit upload in KB/s. No limit by default")
)

type customReader struct {
	Reader io.Reader

	bytes     int64
	lapTime   time.Time
	startTime time.Time
	fileSize  int64
}

func main() {
	flag.Parse()

	if *filename == "" {
		log.Fatalf("You must provide a filename of a video file to upload")
	}

	client, err := buildOAuthHTTPClient(youtube.YoutubeUploadScope)
	if err != nil {
		log.Fatalf("Error building OAuth client: %v", err)
	}

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating YouTube client: %v", err)
	}

	upload := &youtube.Video{
		Snippet: &youtube.VideoSnippet{
			Title:       *title,
			Description: *description,
			CategoryId:  *category,
		},
		Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
	}

	// The API returns a 400 Bad Request response if tags is an empty string.
	if strings.Trim(*keywords, "") != "" {
		upload.Snippet.Tags = strings.Split(*keywords, ",")
	}

	call := service.Videos.Insert("snippet,status", upload)

	reader := &customReader{}
	var lreader io.Reader

	if *rate > 0 {
		// Bucket adding rate KB every second, holding max 100KB
		bucket := ratelimit.NewBucketWithRate(float64(*rate)*1024, 100*1024)
		lreader = ratelimit.Reader(reader, bucket)
	}

	if strings.HasPrefix(*filename, "http") {
		resp, err := http.Head(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		lenStr := resp.Header.Get("content-length")
		if lenStr != "" {
			reader.fileSize, err = strconv.ParseInt(lenStr, 10, 64)
			if err != nil {
				log.Fatal(err)
			}
		}

		resp, err = http.Get(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		reader.Reader = resp.Body
		defer resp.Body.Close()
	} else {
		file, err := os.Open(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		fileInfo, err := file.Stat()
		if err != nil {
			log.Fatalf("Error stating file %v: %v", *filename, err)
		}
		reader.fileSize = fileInfo.Size()
		reader.Reader = file
		defer file.Close()
	}

	// set minimum chunk size so we can see progress
	options := googleapi.ChunkSize(1)
	var video *youtube.Video
	if lreader != nil {
		video, err = call.Media(lreader, options).Do()
	} else {
		video, err = call.Media(reader, options).Do()
	}
	if err != nil {
		log.Fatalf("Error making YouTube API call: %v", err)
	}
	fmt.Printf("\nUpload successful! Video ID: %v\n", video.Id)
}

func (r *customReader) progress(Bps int64) {
	if r.fileSize > 0 {
		eta := time.Duration((r.fileSize-r.bytes)/Bps) * time.Second
		fmt.Printf("\rTransfer rate %.2f Mbps, %d / %d (%.2f%%) ETA %s", float32(Bps*8)/(1000*1000), r.bytes, r.fileSize, float32(r.bytes)/float32(r.fileSize)*100, eta)
	} else {
		fmt.Printf("\rTransfer rate %.2f Mbps, %d", float32(Bps*8)/(1000*1000), r.bytes)
	}
}

func (r *customReader) Read(p []byte) (n int, err error) {
	if r.startTime.IsZero() {
		r.startTime = time.Now()
	}
	if r.lapTime.IsZero() {
		r.lapTime = time.Now()
	}
	if len(p) == 0 {
		return 0, nil
	}
	n, err = r.Reader.Read(p)
	r.bytes += int64(n)

	if time.Since(r.lapTime) >= time.Second || err == io.EOF {
		timeSince := int64(time.Since(r.startTime).Seconds())
		if timeSince == 0 {
			r.progress(r.bytes)
		} else {
			r.progress(r.bytes / timeSince)
		}
		r.lapTime = time.Now()
	}

	return n, err
}
<commit_msg>tweaks<commit_after>/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/juju/ratelimit"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/youtube/v3"
)

var (
	filename     = flag.String("filename", "", "Filename to upload. Can be a URL")
	title        = flag.String("title", "Video Title", "Video title")
	description  = flag.String("description", "uploaded by youtubeuploader", "Video description")
	category     = flag.String("category", "", "Video category")
	keywords     = flag.String("keywords", "", "Comma separated list of video keywords")
	privacy      = flag.String("privacy", "private", "Video privacy status")
	showProgress = flag.Bool("progress", true, "Show progress indicator")
	rate         = flag.Int("ratelimit", 0, "Rate limit upload in KB/s. No limit by default")
)

type customReader struct {
	Reader io.Reader

	bytes     int64
	lapTime   time.Time
	startTime time.Time
	fileSize  int64
}

func main() {
	flag.Parse()

	if *filename == "" {
		log.Fatalf("You must provide a filename of a video file to upload")
	}

	client, err := buildOAuthHTTPClient(youtube.YoutubeUploadScope)
	if err != nil {
		log.Fatalf("Error building OAuth client: %v", err)
	}

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating YouTube client: %v", err)
	}

	upload := &youtube.Video{
		Snippet: &youtube.VideoSnippet{
			Title:       *title,
			Description: *description,
			CategoryId:  *category,
		},
		Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
	}

	// The API returns a 400 Bad Request response if tags is an empty string.
	if strings.Trim(*keywords, "") != "" {
		upload.Snippet.Tags = strings.Split(*keywords, ",")
	}

	call := service.Videos.Insert("snippet,status", upload)

	reader := &customReader{}
	var lreader io.Reader

	if *rate > 0 {
		// Bucket adding rate KB every second, holding max 100KB
		bucket := ratelimit.NewBucketWithRate(float64(*rate)*1024, 100*1024)
		lreader = ratelimit.Reader(reader, bucket)
	}

	if strings.HasPrefix(*filename, "http") {
		resp, err := http.Head(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		lenStr := resp.Header.Get("content-length")
		if lenStr != "" {
			reader.fileSize, err = strconv.ParseInt(lenStr, 10, 64)
			if err != nil {
				log.Fatal(err)
			}
		}

		resp, err = http.Get(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		reader.Reader = resp.Body
		reader.fileSize = resp.ContentLength
		defer resp.Body.Close()
	} else {
		file, err := os.Open(*filename)
		if err != nil {
			log.Fatalf("Error opening %v: %v", *filename, err)
		}
		fileInfo, err := file.Stat()
		if err != nil {
			log.Fatalf("Error stating file %v: %v", *filename, err)
		}
		reader.fileSize = fileInfo.Size()
		reader.Reader = file
		defer file.Close()
	}

	var option googleapi.MediaOption
	if reader.fileSize < (1024 * 1024 * 10) {
		// on small uploads (<10MB), set minimum chunk size so we can see progress
		option = googleapi.ChunkSize(1)
	} else {
		// on larger uploads, use the default chunk size for best performance
		option = googleapi.ChunkSize(googleapi.DefaultUploadChunkSize)
	}

	var video *youtube.Video
	if lreader != nil {
		// rate-limited reader
		video, err = call.Media(lreader, option).Do()
	} else {
		video, err = call.Media(reader, option).Do()
	}
	if err != nil {
		if video != nil {
			log.Fatalf("Error making YouTube API call: %v, %v", err, video.HTTPStatusCode)
		} else {
			log.Fatalf("Error making YouTube API call: %v", err)
		}
	}
	fmt.Printf("\nUpload successful! Video ID: %v\n", video.Id)
}

func (r *customReader) progress(Bps int64) {
	if r.fileSize > 0 {
		eta := time.Duration((r.fileSize-r.bytes)/Bps) * time.Second
		fmt.Printf("\rTransfer rate %.2f Mbps, %d / %d (%.2f%%) ETA %s", float32(Bps*8)/(1000*1000), r.bytes, r.fileSize, float32(r.bytes)/float32(r.fileSize)*100, eta)
	} else {
		fmt.Printf("\rTransfer rate %.2f Mbps, %d", float32(Bps*8)/(1000*1000), r.bytes)
	}
}

func (r *customReader) Read(p []byte) (n int, err error) {
	if r.startTime.IsZero() {
		r.startTime = time.Now()
	}
	if r.lapTime.IsZero() {
		r.lapTime = time.Now()
	}
	if len(p) == 0 {
		return 0, nil
	}
	n, err = r.Reader.Read(p)
	r.bytes += int64(n)

	if time.Since(r.lapTime) >= time.Second || err == io.EOF {
		timeSince := int64(time.Since(r.startTime).Seconds())
		if timeSince == 0 {
			r.progress(r.bytes)
		} else {
			r.progress(r.bytes / timeSince)
		}
		r.lapTime = time.Now()
	}

	return n, err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"

	"github.com/michaelklishin/rabbit-hole"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphdef = map[string](mp.Graphs){
	"rabbitmq.queue": mp.Graphs{
		Label: "RabbitMQ Queue",
		Unit: "integer",
		Metrics:[](mp.Metrics){
			mp.Metrics{Name: "messages", Label: "Total", Diff: false},
			mp.Metrics{Name: "ready", Label: "Ready", Diff: false},
			mp.Metrics{Name: "unacknowledged", Label: "Unacknowledged", Diff:false},
		},
	},
	"rabbitmq.message": mp.Graphs{
		Label: "RabbitMQ Message",
		Unit: "integer",
		Metrics:[](mp.Metrics){
			mp.Metrics{Name: "publish", Label: "Publish", Diff: false},
		},
	},
}

type RabbitMQPlugin struct {
	Url string
	User string
	Password string
	TempFile string
}

func (r RabbitMQPlugin) FetchMetrics() (map[string]interface{},error){
	rmqc, err:= rabbithole.NewClient(r.Url, r.User, r.Password)
	if err != nil {
		return nil, err
	}
	res, err := rmqc.Overview()
	if err != nil {
		return nil, err
	}

	return r.parseStats(*res)
}

func (r RabbitMQPlugin) parseStats(res rabbithole.Overview) (map[string]interface{},error){
	stat := make(map[string]interface{})

	stat["messages"] = float64(res.QueueTotals.Messages)
	stat["ready"] = float64(res.QueueTotals.MessagesReady)
	stat["unacknowledged"] = float64(res.QueueTotals.MessagesUnacknowledged)
	stat["publish"] = float64(res.MessageStats.PublishDetails.Rate)

	return stat, nil

}

func (r RabbitMQPlugin) GraphDefinition() map[string](mp.Graphs){
	return graphdef
}

func main(){
	optURI :=  flag.String("uri", "http://localhost:15672", "URI")
	optUser := flag.String("user", "guest", "User")
	optPass := flag.String("password", "guest", "Password")
	flag.Parse()

	var rabbitmq RabbitMQPlugin

	rabbitmq.Url = *optURI
	rabbitmq.User = *optUser
	rabbitmq.Password = *optPass

	helper := mp.NewMackerelPlugin(rabbitmq)

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != ""{
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<commit_msg>Fix for supporting golint<commit_after>package main

import (
	"flag"
	"os"

	"github.com/michaelklishin/rabbit-hole"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphdef = map[string](mp.Graphs){
	"rabbitmq.queue": mp.Graphs{
		Label: "RabbitMQ Queue",
		Unit: "integer",
		Metrics:[](mp.Metrics){
			mp.Metrics{Name: "messages", Label: "Total", Diff: false},
			mp.Metrics{Name: "ready", Label: "Ready", Diff: false},
			mp.Metrics{Name: "unacknowledged", Label: "Unacknowledged", Diff:false},
		},
	},
	"rabbitmq.message": mp.Graphs{
		Label: "RabbitMQ Message",
		Unit: "integer",
		Metrics:[](mp.Metrics){
			mp.Metrics{Name: "publish", Label: "Publish", Diff: false},
		},
	},
}

// RabbitMQPlugin metrics
type RabbitMQPlugin struct {
	URI string
	User string
	Password string
	TempFile string
}

// FetchMetrics interface for mackerelplugin
func (r RabbitMQPlugin) FetchMetrics() (map[string]interface{},error){
	rmqc, err:= rabbithole.NewClient(r.URI, r.User, r.Password)
	if err != nil {
		return nil, err
	}
	res, err := rmqc.Overview()
	if err != nil {
		return nil, err
	}

	return r.parseStats(*res)
}

func (r RabbitMQPlugin) parseStats(res rabbithole.Overview) (map[string]interface{},error){
	stat := make(map[string]interface{})

	stat["messages"] = float64(res.QueueTotals.Messages)
	stat["ready"] = float64(res.QueueTotals.MessagesReady)
	stat["unacknowledged"] = float64(res.QueueTotals.MessagesUnacknowledged)
	stat["publish"] = float64(res.MessageStats.PublishDetails.Rate)

	return stat, nil

}

// GraphDefinition interface for mackerel plugin
func (r RabbitMQPlugin) GraphDefinition() map[string](mp.Graphs){
	return graphdef
}

func main(){
	optURI :=  flag.String("uri", "http://localhost:15672", "URI")
	optUser := flag.String("user", "guest", "User")
	optPass := flag.String("password", "guest", "Password")
	flag.Parse()

	var rabbitmq RabbitMQPlugin

	rabbitmq.URI = *optURI
	rabbitmq.User = *optUser
	rabbitmq.Password = *optPass

	helper := mp.NewMackerelPlugin(rabbitmq)

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != ""{
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<|endoftext|>


<commit_before>package twse

import (
	"fmt"
	"log"
	"testing"
	"time"

	"github.com/toomore/gogrs/tradingdays"
	"github.com/toomore/gogrs/utils"
)

func TestLists_Get_Rawdata(*testing.T) {
	l := NewLists(time.Date(2014, 12, 23, 0, 0, 0, 0, utils.TaipeiTimeZone))
	//listdata, err := l.Get("MS")
	//fmt.Println(l.categoryRawData, "\n\n", listdata, err)
	//l.FmtData
	l.Get("MS")
	l.Get("ms")
}

func TestLists_Get_categoryNoList(t *testing.T) {
	l := NewLists(time.Date(2015, 4, 27, 0, 0, 0, 0, utils.TaipeiTimeZone))
	l.Get("15") //航運業
	l.Get("01") //水泥業
	t.Log(l.FmtData["2618"])
	t.Log(l.FmtData)
	t.Log(l.categoryRawData)
	t.Log(l.categoryNoList)
	t.Log(l.GetCategoryList("15"))
	t.Log("ALLBUT0999:", len(l.GetCategoryList("ALLBUT0999")))
	t.Log("ALL:", len(l.GetCategoryList("ALL")))
	ll := NewLists(time.Date(2015, 5, 22, 0, 0, 0, 0, utils.TaipeiTimeZone))
	if len(ll.GetCategoryList("ALLBUT0999")) < 10 {
		t.Error("應該沒那麼少")
	}
	if len(ll.GetCategoryList("ALL")) < 10 {
		t.Error("應該沒那麼少")
	}
}

func TestOTCLists(t *testing.T) {
	o := NewOTCLists(tradingdays.FindRecentlyOpened(time.Now()))
	log.Println(o.Get("04"))
	log.Println(o.GetCategoryList("04"))
}

func TestCategoryList(t *testing.T) {
	categoryList := NewCategoryList()
	t.Log(categoryList.Same())
	t.Log(categoryList.OnlyTWSE())
	t.Log(categoryList.OnlyOTC())
}

func ExampleLists_GetCategoryList() {
	l := NewLists(time.Date(2015, 4, 27, 0, 0, 0, 0, utils.TaipeiTimeZone))
	categoryList := l.GetCategoryList("15")
	for _, v := range categoryList {
		if v.No == "2618" {
			fmt.Printf("%+v", v)
			break
		}
	}
	// output:
	// {No:2618 Name:長榮航}
}

func ExampleLists_Get_fmtData() {
	l := NewLists(time.Date(2015, 4, 9, 0, 0, 0, 0, utils.TaipeiTimeZone))
	l.Get("15") //航運業
	fmt.Printf("%+v", l.FmtData["2618"])
	// output:
	// {No:2618 Name:長榮航 Volume:46670950 TotalPrice:1136982254 Open:24 High:24.65 Low:24 Price:24 Range:0.55 Totalsale:11117 LastBuyPrice:24 LastBuyVolume:2027 LastSellPrice:24.1 LastSellVolume:10 PERatio:0 IssuedShares:0}
}

func ExampleLists_Get() {
	l := NewLists(time.Date(2014, 12, 26, 0, 0, 0, 0, utils.TaipeiTimeZone))
	listdata, _ := l.Get("15") //航運業
	fmt.Println(listdata[0])
	// output:
	// [2208   台船   729340 324 12048156 16.45 16.6 16.45 16.45   0 16.45 67 16.5 58 41.13]
}

func ExampleLists_Get_notEnoughData() {
	year, month, day := time.Now().Date()
	l := NewLists(time.Date(year, month+1, day, 0, 0, 0, 0, utils.TaipeiTimeZone))
	_, err := l.Get("15") //航運業
	fmt.Println(err)
	// output:
	// Not enough data.
}
<commit_msg>Tiny changed in twse/twselist testing.<commit_after>package twse

import (
	"fmt"
	"log"
	"testing"
	"time"

	"github.com/toomore/gogrs/tradingdays"
	"github.com/toomore/gogrs/utils"
)

func TestLists_Get_Rawdata(*testing.T) {
	l := NewLists(time.Date(2014, 12, 23, 0, 0, 0, 0, utils.TaipeiTimeZone))
	//listdata, err := l.Get("MS")
	//fmt.Println(l.categoryRawData, "\n\n", listdata, err)
	//l.FmtData
	l.Get("MS")
	l.Get("ms")
}

func TestLists_Get_categoryNoList(t *testing.T) {
	l := NewLists(time.Date(2015, 4, 27, 0, 0, 0, 0, utils.TaipeiTimeZone))
	l.Get("15") //航運業
	l.Get("01") //水泥業
	t.Log(l.FmtData["2618"])
	t.Log(l.FmtData)
	t.Log(l.categoryRawData)
	t.Log(l.categoryNoList)
	t.Log(l.GetCategoryList("15"))
	t.Log("ALLBUT0999:", len(l.GetCategoryList("ALLBUT0999")))
	t.Log("ALL:", len(l.GetCategoryList("ALL")))
	ll := NewLists(time.Date(2015, 5, 22, 0, 0, 0, 0, utils.TaipeiTimeZone))
	if len(ll.GetCategoryList("ALLBUT0999")) < 10 {
		t.Error("應該沒那麼少")
	}
	if len(ll.GetCategoryList("ALL")) < 10 {
		t.Error("應該沒那麼少")
	}
}

func TestOTCLists(t *testing.T) {
	o := NewOTCLists(tradingdays.FindRecentlyOpened(time.Now()))
	log.Println(o.GetCategoryList("04"))
	log.Println(o.Get("04"))
}

func TestCategoryList(t *testing.T) {
	categoryList := NewCategoryList()
	t.Log(categoryList.Same())
	t.Log(categoryList.OnlyTWSE())
	t.Log(categoryList.OnlyOTC())
}

func ExampleLists_GetCategoryList() {
	l := NewLists(time.Date(2015, 4, 27, 0, 0, 0, 0, utils.TaipeiTimeZone))
	categoryList := l.GetCategoryList("15")
	for _, v := range categoryList {
		if v.No == "2618" {
			fmt.Printf("%+v", v)
			break
		}
	}
	// output:
	// {No:2618 Name:長榮航}
}

func ExampleLists_Get_fmtData() {
	l := NewLists(time.Date(2015, 4, 9, 0, 0, 0, 0, utils.TaipeiTimeZone))
	l.Get("15") //航運業
	fmt.Printf("%+v", l.FmtData["2618"])
	// output:
	// {No:2618 Name:長榮航 Volume:46670950 TotalPrice:1136982254 Open:24 High:24.65 Low:24 Price:24 Range:0.55 Totalsale:11117 LastBuyPrice:24 LastBuyVolume:2027 LastSellPrice:24.1 LastSellVolume:10 PERatio:0 IssuedShares:0}
}

func ExampleLists_Get() {
	l := NewLists(time.Date(2014, 12, 26, 0, 0, 0, 0, utils.TaipeiTimeZone))
	listdata, _ := l.Get("15") //航運業
	fmt.Println(listdata[0])
	// output:
	// [2208   台船   729340 324 12048156 16.45 16.6 16.45 16.45   0 16.45 67 16.5 58 41.13]
}

func ExampleLists_Get_notEnoughData() {
	year, month, day := time.Now().Date()
	l := NewLists(time.Date(year, month+1, day, 0, 0, 0, 0, utils.TaipeiTimeZone))
	_, err := l.Get("15") //航運業
	fmt.Println(err)
	// output:
	// Not enough data.
}
<|endoftext|>


<commit_before>package inmemory

import (
	"errors"
	"sync"
	"time"

	"github.com/cafebazaar/hafezieh"
)

var (
	ErrSmallDuration = errors.New("less than 5 seconds isn't supported by this engine")
)

type InMemoryCache struct {
	config *InMemoryCacheConfig

	items           map[string]*InMemItem
	revisitTimeQMan *revisitTimeQueueManager
	mutex           sync.RWMutex
	janitor         *janitor
}

type InMemoryCacheConfig struct {
	RevisitDefaultDuration time.Duration `mapstructure:"revisit-default-duration"`
	RevisitNumberOfWorkers int           `mapstructure:"revisit-number-of-workers"`
	RevisitClock           time.Duration `mapstructure:"revisit-clock"`
	RevisitFunc            RevisitFunc

	Cleanup *InMemoryCleanupConfig `mapstructure:"cleanup"`
}

func (config *InMemoryCacheConfig) validateAndSetDefaults() error {
	if config.RevisitNumberOfWorkers > 0 {
		if config.RevisitClock == 0 {
			config.RevisitClock = 30 * time.Second
		}
		if config.RevisitFunc == nil {
			return errors.New("No RevisitFunc is set but RevisitNumberOfWorkers is greater than 0")
		}
	}

	if config.Cleanup != nil {
		err := config.Cleanup.validateAndSetDefaults()
		if err != nil {
			return err
		}
	}

	return nil
}

type InMemItem struct {
	Item       interface{}
	CreatedAt  time.Time
	LastAccess time.Time
	Hits       uint

	index       int
	revisitTime *time.Time
}

func (c *InMemoryCache) Set(key string, x interface{}, revisitDuration time.Duration) error {
	if revisitDuration < 0 {
		return hafezieh.ErrNegativeDuration
	}
	if revisitDuration == hafezieh.UseDefaultValue {
		revisitDuration = c.config.RevisitDefaultDuration
	}
	if revisitDuration > 0 && revisitDuration < (5*time.Second) {
		return ErrSmallDuration
	}

	c.mutex.Lock()
	n := time.Now()
	var revisitTime *time.Time
	if revisitDuration > 0 {
		r := n.Add(revisitDuration)
		revisitTime = &r
	}
	c.items[key] = &InMemItem{
		Item:        x,
		CreatedAt:   n,
		LastAccess:  n,
		Hits:        0,
		revisitTime: revisitTime,
	}
	if c.revisitTimeQMan != nil && revisitTime != nil {
		c.revisitTimeQMan.Push(&InMemKey{
			key:         key,
			revisitTime: *revisitTime,
		})
	}
	c.mutex.Unlock()
	return nil
}

func (c *InMemoryCache) Get(key string) (interface{}, error) {
	c.mutex.RLock()
	inMemItem, found := c.items[key]
	c.mutex.RUnlock()
	if found {
		inMemItem.LastAccess = time.Now() // Not guaranteed to always increase
		inMemItem.Hits++                  // Not guaranteed to be accurate
		return inMemItem.Item, nil
	}
	return nil, hafezieh.ErrMiss
}

func (c *InMemoryCache) Del(key string) error {
	c.mutex.Lock()
	delete(c.items, key)
	c.mutex.Unlock()
	return nil
}

func (c *InMemoryCache) Close() error {
	if c.revisitTimeQMan != nil {
		c.revisitTimeQMan.Close()
	}
	c.janitor.stop()
	return nil
}

func (c *InMemoryCache) callRevisit(inMemKey *InMemKey) {
	revisitFunc := c.config.RevisitFunc
	if revisitFunc == nil {
		return
	}
	if inMemItem, found := c.items[inMemKey.key]; found {
		if inMemItem.revisitTime != nil && *inMemItem.revisitTime == inMemKey.revisitTime {
			// Not an old hook
			revisitFunc(c, inMemKey.key, inMemItem)
		}
	}
}

func NewMemoryCache(config *InMemoryCacheConfig) (hafezieh.Cache, error) {
	err := config.validateAndSetDefaults()
	if err != nil {
		return nil, err
	}

	c := &InMemoryCache{
		config: config,

		items: make(map[string]*InMemItem),
	}
	if c.config.RevisitNumberOfWorkers > 0 {
		c.revisitTimeQMan = initRevisitTimeQueueManager(&c.mutex, config.RevisitClock, config.RevisitNumberOfWorkers, c.callRevisit)
	}

	if c.config.Cleanup != nil {
		c.janitor, err = newJanitor(c.config.Cleanup, c)
		if err != nil {
			return nil, err
		}
	}

	return c, nil
}
<commit_msg>RLock on map read, to avoid panic<commit_after>package inmemory

import (
	"errors"
	"sync"
	"time"

	"github.com/cafebazaar/hafezieh"
)

var (
	ErrSmallDuration = errors.New("less than 5 seconds isn't supported by this engine")
)

type InMemoryCache struct {
	config *InMemoryCacheConfig

	items           map[string]*InMemItem
	revisitTimeQMan *revisitTimeQueueManager
	mutex           sync.RWMutex
	janitor         *janitor
}

type InMemoryCacheConfig struct {
	RevisitDefaultDuration time.Duration `mapstructure:"revisit-default-duration"`
	RevisitNumberOfWorkers int           `mapstructure:"revisit-number-of-workers"`
	RevisitClock           time.Duration `mapstructure:"revisit-clock"`
	RevisitFunc            RevisitFunc

	Cleanup *InMemoryCleanupConfig `mapstructure:"cleanup"`
}

func (config *InMemoryCacheConfig) validateAndSetDefaults() error {
	if config.RevisitNumberOfWorkers > 0 {
		if config.RevisitClock == 0 {
			config.RevisitClock = 30 * time.Second
		}
		if config.RevisitFunc == nil {
			return errors.New("No RevisitFunc is set but RevisitNumberOfWorkers is greater than 0")
		}
	}

	if config.Cleanup != nil {
		err := config.Cleanup.validateAndSetDefaults()
		if err != nil {
			return err
		}
	}

	return nil
}

type InMemItem struct {
	Item       interface{}
	CreatedAt  time.Time
	LastAccess time.Time
	Hits       uint

	index       int
	revisitTime *time.Time
}

func (c *InMemoryCache) Set(key string, x interface{}, revisitDuration time.Duration) error {
	if revisitDuration < 0 {
		return hafezieh.ErrNegativeDuration
	}
	if revisitDuration == hafezieh.UseDefaultValue {
		revisitDuration = c.config.RevisitDefaultDuration
	}
	if revisitDuration > 0 && revisitDuration < (5*time.Second) {
		return ErrSmallDuration
	}

	c.mutex.Lock()
	n := time.Now()
	var revisitTime *time.Time
	if revisitDuration > 0 {
		r := n.Add(revisitDuration)
		revisitTime = &r
	}
	c.items[key] = &InMemItem{
		Item:        x,
		CreatedAt:   n,
		LastAccess:  n,
		Hits:        0,
		revisitTime: revisitTime,
	}
	if c.revisitTimeQMan != nil && revisitTime != nil {
		c.revisitTimeQMan.Push(&InMemKey{
			key:         key,
			revisitTime: *revisitTime,
		})
	}
	c.mutex.Unlock()
	return nil
}

func (c *InMemoryCache) Get(key string) (interface{}, error) {
	c.mutex.RLock()
	inMemItem, found := c.items[key]
	c.mutex.RUnlock()
	if found {
		inMemItem.LastAccess = time.Now() // Not guaranteed to always increase
		inMemItem.Hits++                  // Not guaranteed to be accurate
		return inMemItem.Item, nil
	}
	return nil, hafezieh.ErrMiss
}

func (c *InMemoryCache) Del(key string) error {
	c.mutex.Lock()
	delete(c.items, key)
	c.mutex.Unlock()
	return nil
}

func (c *InMemoryCache) Close() error {
	if c.revisitTimeQMan != nil {
		c.revisitTimeQMan.Close()
	}
	c.janitor.stop()
	return nil
}

func (c *InMemoryCache) callRevisit(inMemKey *InMemKey) {
	revisitFunc := c.config.RevisitFunc
	if revisitFunc == nil {
		return
	}
	c.mutex.RLock()
	if inMemItem, found := c.items[inMemKey.key]; found {
		c.mutex.RUnlock()
		if inMemItem.revisitTime != nil && *inMemItem.revisitTime == inMemKey.revisitTime {
			// Not an old hook
			revisitFunc(c, inMemKey.key, inMemItem)
		}
		return
	}
	c.mutex.RUnlock()
}

func NewMemoryCache(config *InMemoryCacheConfig) (hafezieh.Cache, error) {
	err := config.validateAndSetDefaults()
	if err != nil {
		return nil, err
	}

	c := &InMemoryCache{
		config: config,

		items: make(map[string]*InMemItem),
	}
	if c.config.RevisitNumberOfWorkers > 0 {
		c.revisitTimeQMan = initRevisitTimeQueueManager(&c.mutex, config.RevisitClock, config.RevisitNumberOfWorkers, c.callRevisit)
	}

	if c.config.Cleanup != nil {
		c.janitor, err = newJanitor(c.config.Cleanup, c)
		if err != nil {
			return nil, err
		}
	}

	return c, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"regexp"
)

type Tagger struct {
	Movie Movie
	File  File
}

func (t *Tagger) TmpFileName() string {
	return fmt.Sprintf("%s%s%s", t.File.FileName, t.TempId(), t.File.Format)
}

func (t *Tagger) TempId() string {
	var file_id string
	pwd, _ := os.Getwd()
	files, _ := ioutil.ReadDir(pwd)
	for _, f := range files {
		r, _ := regexp.Compile("-temp-([0-9]+)")
		if r.MatchString(f.Name()) {
			file_id = r.FindString(f.Name())
		}
	}
	return file_id
}

func (t *Tagger) GetArtwork() {
	if t.Movie.HasArtwork() {
		println("Downloading artwork")
		file, err := os.Create("artwork.jpg")
		defer file.Close()

		check := http.Client{
			CheckRedirect: func(r *http.Request, via []*http.Request) error {
				r.URL.Opaque = r.URL.Path
				return nil
			},
		}

		resp, err := check.Get(t.Movie.ArtworkUrl) // add a filter to check redirect
		if err != nil {
			fmt.Println(err)
			panic(err)
		}
		defer resp.Body.Close()
		io.Copy(file, resp.Body)

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

func (t *Tagger) AtomicCommand() {
	file_args := []string{t.File.FullPath}
	args := append(file_args, t.Movie.ParsleyFlags()...)

	if t.Movie.HasArtwork() {
		artwork := []string{"--artwork", "REMOVE_ALL", "--artwork", "artwork.jpg"}
		args = append(args, artwork...)
	} else {
		println("Could not find artwork")
	}

	if t.Movie.IsValid() {
		println("Setting tags")
		exec.Command("AtomicParsley", args...).Output()
	} else {
		println("Could not find IMDB info")
	}
}

func (t *Tagger) CleanupCommand() {
	println("Cleaning up tmp files")
	os.Remove("artwork.jpg")
	os.Rename(t.TmpFileName(), t.File.FullPath)
}

func (t *Tagger) SetTags() {
	t.GetArtwork()
	t.AtomicCommand()
	t.CleanupCommand()
}
<commit_msg>Add go style names<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"regexp"
)

type Tagger struct {
	Movie Movie
	File  File
}

func (t *Tagger) TmpFileName() string {
	return fmt.Sprintf("%s%s%s", t.File.FileName, t.TempID(), t.File.Format)
}

func (t *Tagger) TempID() string {
	var fileID string
	pwd, _ := os.Getwd()
	files, _ := ioutil.ReadDir(pwd)
	for _, f := range files {
		r, _ := regexp.Compile("-temp-([0-9]+)")
		if r.MatchString(f.Name()) {
			fileID = r.FindString(f.Name())
		}
	}
	return fileID
}

func (t *Tagger) GetArtwork() {
	if t.Movie.HasArtwork() {
		println("Downloading artwork")
		file, err := os.Create("artwork.jpg")
		defer file.Close()

		check := http.Client{
			CheckRedirect: func(r *http.Request, via []*http.Request) error {
				r.URL.Opaque = r.URL.Path
				return nil
			},
		}

		resp, err := check.Get(t.Movie.ArtworkUrl) // add a filter to check redirect
		if err != nil {
			fmt.Println(err)
			panic(err)
		}
		defer resp.Body.Close()
		io.Copy(file, resp.Body)

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

func (t *Tagger) AtomicCommand() {
	fileArgs := []string{t.File.FullPath}
	args := append(fileArgs, t.Movie.ParsleyFlags()...)

	if t.Movie.HasArtwork() {
		artwork := []string{"--artwork", "REMOVE_ALL", "--artwork", "artwork.jpg"}
		args = append(args, artwork...)
	} else {
		println("Could not find artwork")
	}

	if t.Movie.IsValid() {
		println("Setting tags")
		exec.Command("AtomicParsley", args...).Output()
	} else {
		println("Could not find IMDB info")
	}
}

func (t *Tagger) CleanupCommand() {
	println("Cleaning up tmp files")
	os.Remove("artwork.jpg")
	os.Rename(t.TmpFileName(), t.File.FullPath)
}

func (t *Tagger) SetTags() {
	t.GetArtwork()
	t.AtomicCommand()
	t.CleanupCommand()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"testing"
)

var (
	v4dir             = "aws4_testsuite"
	v4CredentialScope = "20110909/us-east-1/host/aws4_request"
	v4SecretKey       = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
)

type v4TestFiles struct {
	base  string
	req   []byte
	creq  []byte
	sts   []byte
	authz []byte
	sreq  []byte

	request *http.Request
}

// http://docs.amazonwebservices.com/general/latest/gr/signature-v4-test-suite.html
func testFiles(dir string) ([]string, error) {
	d, err := os.Open(dir)
	if err != nil {
		return nil, err
	}
	f, err := d.Readdirnames(0)
	if err != nil {
		return nil, err
	}

	sort.Strings(f)

	tests := make([]string, 0)
	for i := 0; i < len(f)-4; {
		if filepath.Ext(f[i]) == ".authz" &&
			filepath.Ext(f[i+1]) == ".creq" &&
			filepath.Ext(f[i+2]) == ".req" &&
			filepath.Ext(f[i+3]) == ".sreq" &&
			filepath.Ext(f[i+4]) == ".sts" {
			tests = append(tests, f[i][:len(f[i])-6])
			i += 5
		} else {
			i++
		}
	}

	return tests, nil
}

func readTestFiles(files []string, t *testing.T) chan *v4TestFiles {
	ch := make(chan *v4TestFiles)
	go func() {
		for _, f := range files {
			var err error
			d := new(v4TestFiles)
			d.base = f

			// read in the raw request and convert it to go's internal format
			d.req, err = ioutil.ReadFile(v4dir + "/" + f + ".req")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}
			// go doesn't like post requests with spaces in them
			if d.base == "post-vanilla-query-nonunreserved" ||
				d.base == "post-vanilla-query-space" {
				// skip tests with spacing in URLs or invalid escapes
				continue
			} else {
				// go doesn't like lowercase http
				fixed := bytes.Replace(d.req, []byte("http"), []byte("HTTP"), 1)
				reader := bufio.NewReader(bytes.NewBuffer(fixed))
				d.request, err = http.ReadRequest(reader)
				if err != nil {
					t.Error("parsing", d.base, "request", err)
					continue
				}
				if i := bytes.Index(d.req, []byte("\n\n")); i != -1 {
					d.request.Body = ioutil.NopCloser(bytes.NewBuffer(d.req[i+2:]))
				}
			}

			d.creq, err = ioutil.ReadFile(v4dir + "/" + f + ".creq")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			d.sts, err = ioutil.ReadFile(v4dir + "/" + f + ".sts")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			d.authz, err = ioutil.ReadFile(v4dir + "/" + f + ".authz")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			ch <- d
		}
		close(ch)
	}()
	return ch
}

func TestSignatureVersion4(t *testing.T) {
	files, err := testFiles(v4dir)
	if err != nil {
		t.Fatal(err)
	}
	tests := readTestFiles(files, t)
	var headers []string
	var cr []byte
	for f := range tests {
		cr, headers, err = CreateCanonicalRequest(f.request)
		if err != nil {
			t.Error(f.base, err)
			continue
		}
		if !bytes.Equal(cr, f.creq) {
			t.Error(f.base, "canonical request")
			t.Logf("got:\n%s", string(cr))
			t.Logf("want:\n%s", string(f.creq))
			continue
		}
		var sts []byte
		date, ok := f.request.Header["Date"]
		if ok && len(date) > 0 {
			sts, err = CreateStringToSign(cr, date[0], v4CredentialScope)
			if err != nil {
				t.Error(f.base, err)
				continue
			}
			if !bytes.Equal(sts, f.sts) {
				t.Error(f.base, "string to sign")
				t.Logf("got:\n%s", string(sts))
				t.Logf("want:\n%s", string(f.sts))
				continue
			}
		} else {
			t.Error(f.base, "no date")
			t.Log(f.request)
			continue
		}

		sig, err := CreateSignature("20110909", "us-east-1", "host", sts)
		if err != nil {
			t.Error(err)
			continue
		}
		authz := []byte("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/")
		authz = append(authz, v4CredentialScope...)
		authz = append(authz, ", SignedHeaders="...)
		for i := range headers {
			if i > 0 {
				authz = append(authz, ';')
			}
			authz = append(authz, headers[i]...)
		}
		authz = append(authz, ", Signature="...)
		authz = append(authz, sig...)

		if !bytes.Equal(authz, f.authz) {
			t.Error(f.base, "signed signature")
			t.Logf("got:\n%s", authz)
			t.Logf("want:\n%s", f.authz)
		}
	}
}
<commit_msg>Passing all tests.<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"testing"
)

var (
	v4dir             = "aws4_testsuite"
	v4CredentialScope = "20110909/us-east-1/host/aws4_request"
	v4SecretKey       = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
)

type v4TestFiles struct {
	base  string
	req   []byte
	creq  []byte
	sts   []byte
	authz []byte
	sreq  []byte

	request *http.Request
	body    io.ReadSeeker
}

// http://docs.amazonwebservices.com/general/latest/gr/signature-v4-test-suite.html
func testFiles(dir string) ([]string, error) {
	d, err := os.Open(dir)
	if err != nil {
		return nil, err
	}
	f, err := d.Readdirnames(0)
	if err != nil {
		return nil, err
	}

	sort.Strings(f)

	tests := make([]string, 0)
	for i := 0; i < len(f)-4; {
		if filepath.Ext(f[i]) == ".authz" &&
			filepath.Ext(f[i+1]) == ".creq" &&
			filepath.Ext(f[i+2]) == ".req" &&
			filepath.Ext(f[i+3]) == ".sreq" &&
			filepath.Ext(f[i+4]) == ".sts" {
			tests = append(tests, f[i][:len(f[i])-6])
			i += 5
		} else {
			i++
		}
	}

	return tests, nil
}

func readTestFiles(files []string, t *testing.T) chan *v4TestFiles {
	ch := make(chan *v4TestFiles)
	go func() {
		for _, f := range files {
			var err error
			d := new(v4TestFiles)
			d.base = f

			// read in the raw request and convert it to go's internal format
			d.req, err = ioutil.ReadFile(v4dir + "/" + f + ".req")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}
			// go doesn't like post requests with spaces in them
			if d.base == "post-vanilla-query-nonunreserved" ||
				d.base == "post-vanilla-query-space" {
				// skip tests with spacing in URLs or invalid escapes
				continue
			} else {
				// go doesn't like lowercase http
				fixed := bytes.Replace(d.req, []byte("http"), []byte("HTTP"), 1)
				reader := bufio.NewReader(bytes.NewBuffer(fixed))
				d.request, err = http.ReadRequest(reader)
				if err != nil {
					t.Error("parsing", d.base, "request", err)
					continue
				}
				delete(d.request.Header, "User-Agent")
				if i := bytes.Index(d.req, []byte("\n\n")); i != -1 {
					d.body = bytes.NewReader(d.req[i+2:])
					d.request.Body = ioutil.NopCloser(d.body)
				}
			}

			d.creq, err = ioutil.ReadFile(v4dir + "/" + f + ".creq")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			d.sts, err = ioutil.ReadFile(v4dir + "/" + f + ".sts")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			d.authz, err = ioutil.ReadFile(v4dir + "/" + f + ".authz")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			d.sreq, err = ioutil.ReadFile(v4dir + "/" + f + ".sreq")
			if err != nil {
				t.Error("reading", d.base, err)
				continue
			}

			ch <- d
		}
		close(ch)
	}()
	return ch
}

func TestSignatureVersion4(t *testing.T) {
	files, err := testFiles(v4dir)
	if err != nil {
		t.Fatal(err)
	}
	tests := readTestFiles(files, t)
	var headers []string
	var cr []byte
	for f := range tests {
		cr, headers, err = CreateCanonicalRequest(f.request)
		if err != nil {
			t.Error(f.base, err)
			continue
		}
		if !bytes.Equal(cr, f.creq) {
			t.Error(f.base, "canonical request")
			t.Logf("got:\n%s", string(cr))
			t.Logf("want:\n%s", string(f.creq))
			continue
		}
		var sts []byte
		date, ok := f.request.Header["Date"]
		if ok && len(date) > 0 {
			sts, err = CreateStringToSign(cr, date[0], v4CredentialScope)
			if err != nil {
				t.Error(f.base, err)
				continue
			}
			if !bytes.Equal(sts, f.sts) {
				t.Error(f.base, "string to sign")
				t.Logf("got:\n%s", string(sts))
				t.Logf("want:\n%s", string(f.sts))
				continue
			}
		} else {
			t.Error(f.base, "no date")
			t.Log(f.request)
			continue
		}

		sig, err := CreateSignature("20110909", "us-east-1", "host", sts)
		if err != nil {
			t.Error(err)
			continue
		}
		authz := []byte("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/")
		authz = append(authz, v4CredentialScope...)
		authz = append(authz, ", SignedHeaders="...)
		for i := range headers {
			if i > 0 {
				authz = append(authz, ';')
			}
			authz = append(authz, headers[i]...)
		}
		authz = append(authz, ", Signature="...)
		authz = append(authz, sig...)
		if !bytes.Equal(authz, f.authz) {
			t.Error(f.base, "signed signature")
			t.Logf("got:\n%s", authz)
			t.Logf("want:\n%s", f.authz)
		}

		var sreqBuffer bytes.Buffer
		i := bytes.Index(f.req, []byte("\n\n"))
		_, err = sreqBuffer.Write(f.req[:i+1])
		if err != nil {
			t.Error(err)
			continue
		}
		_, err = sreqBuffer.WriteString(fmt.Sprintf("Authorization: %s\n\n",
			authz))
		if err != nil {
			t.Error(err)
			continue
		}
		f.body.Seek(0, 0)
		_, err = io.Copy(&sreqBuffer, f.request.Body)
		if err != nil {
			t.Error(err)
			continue
		}
		sreq := sreqBuffer.Bytes()
		if !bytes.Equal(sreq, f.sreq) {
			t.Error(f.base, "signed request")
			t.Logf("got:\n%s", sreq)
			t.Logf("want:\n%s", f.sreq)
		}
	}
}
<|endoftext|>


<commit_before>package fizz

type Table struct {
	Name    string `db:"name"`
	Columns []Column
	Indexes []Index
}

func (t *Table) Column(name string, colType string, options map[string]interface{}) {
	var primary bool
	if _, ok := options["primary"]; ok {
		primary = true
	}
	c := Column{
		Name:    name,
		ColType: colType,
		Options: options,
		Primary: primary,
	}
	t.Columns = append(t.Columns, c)
}

func (t *Table) Timestamp(name string) {
	c := Column{
		Name:    name,
		ColType: "timestamp",
		Options: Options{},
	}

	t.Columns = append(t.Columns, c)
}

func (t *Table) Timestamps() {
	t.Columns = append(t.Columns, []Column{CREATED_COL, UPDATED_COL}...)
}

func (t *Table) ColumnNames() []string {
	cols := make([]string, len(t.Columns))
	for i, c := range t.Columns {
		cols[i] = c.Name
	}
	return cols
}

func (t *Table) HasColumns(args ...string) bool {
	keys := map[string]struct{}{}
	for _, k := range t.ColumnNames() {
		keys[k] = struct{}{}
	}
	for _, a := range args {
		if _, ok := keys[a]; !ok {
			return false
		}
	}
	return true
}

func (f fizzer) CreateTable() interface{} {
	return func(name string, fn func(t *Table), options map[string]interface{}) {
		t := Table{
			Name:    name,
			Columns: []Column{},
		}
		fn(&t)
		var foundPrimary bool
		for _, c := range t.Columns {
			if c.Primary {
				foundPrimary = true
				break
			}
		}

		if !foundPrimary {
			t.Columns = append([]Column{INT_ID_COL}, t.Columns...)
		}

		if value, exists := options["timestamps"]; !exists || true == value {
			t.Columns = append(t.Columns, CREATED_COL, UPDATED_COL)
		}

		f.add(f.Bubbler.CreateTable(t))
	}
}

func (f fizzer) DropTable() interface{} {
	return func(name string) {
		f.add(f.Bubbler.DropTable(Table{Name: name}))
	}
}

func (f fizzer) RenameTable() interface{} {
	return func(old, new string) {
		f.add(f.Bubbler.RenameTable([]Table{
			{Name: old},
			{Name: new},
		}))
	}
}
<commit_msg>disable timestamps moved to a function<commit_after>package fizz

type Table struct {
	Name    string `db:"name"`
	Columns []Column
	Indexes []Index
	Options map[string]interface{}
}

func (t *Table) DisableTimestamps() {
	t.Options["timestamps"] = false
}

func (t *Table) Column(name string, colType string, options map[string]interface{}) {
	var primary bool
	if _, ok := options["primary"]; ok {
		primary = true
	}
	c := Column{
		Name:    name,
		ColType: colType,
		Options: options,
		Primary: primary,
	}
	t.Columns = append(t.Columns, c)
}

func (t *Table) Timestamp(name string) {
	c := Column{
		Name:    name,
		ColType: "timestamp",
		Options: Options{},
	}

	t.Columns = append(t.Columns, c)
}

func (t *Table) Timestamps() {
	t.Columns = append(t.Columns, []Column{CREATED_COL, UPDATED_COL}...)
}

func (t *Table) ColumnNames() []string {
	cols := make([]string, len(t.Columns))
	for i, c := range t.Columns {
		cols[i] = c.Name
	}
	return cols
}

func (t *Table) HasColumns(args ...string) bool {
	keys := map[string]struct{}{}
	for _, k := range t.ColumnNames() {
		keys[k] = struct{}{}
	}
	for _, a := range args {
		if _, ok := keys[a]; !ok {
			return false
		}
	}
	return true
}

func (f fizzer) CreateTable() interface{} {
	return func(name string, fn func(t *Table)) {
		t := Table{
			Name:    name,
			Columns: []Column{},
		}

		fn(&t)
		var foundPrimary bool
		for _, c := range t.Columns {
			if c.Primary {
				foundPrimary = true
				break
			}
		}

		if !foundPrimary {
			t.Columns = append([]Column{INT_ID_COL}, t.Columns...)
		}

		if enabled, exists := t.Options["timestamps"]; !exists || enabled == true {
			t.Timestamps()
		}

		f.add(f.Bubbler.CreateTable(t))
	}
}

func (f fizzer) DropTable() interface{} {
	return func(name string) {
		f.add(f.Bubbler.DropTable(Table{Name: name}))
	}
}

func (f fizzer) RenameTable() interface{} {
	return func(old, new string) {
		f.add(f.Bubbler.RenameTable([]Table{
			{Name: old},
			{Name: new},
		}))
	}
}
<|endoftext|>


<commit_before>package skiplist

import "bytes"

func compareElement(a *SkipListElement, key []byte) int {
	if len(a.Key) == 0 {
		return -1
	}
	return bytes.Compare(a.Key, key)
}

func (node *SkipListElement) Reference() *SkipListElementReference {
	if node == nil {
		return nil
	}
	return &SkipListElementReference{
		ElementPointer: node.Id,
		Key:            node.Key,
	}
}

func (t *SkipList) saveElement(element *SkipListElement) error {
	if element == nil {
		return nil
	}
	return t.listStore.SaveElement(element.Id, element)
}

func (t *SkipList) deleteElement(element *SkipListElement) error {
	if element == nil {
		return nil
	}
	return t.listStore.DeleteElement(element.Id)
}

func (t *SkipList) loadElement(ref *SkipListElementReference) (*SkipListElement, error) {
	if ref == nil {
		return nil, nil
	}
	return t.listStore.LoadElement(ref.ElementPointer)
}
<commit_msg>SkipListElementReference can be an empty object<commit_after>package skiplist

import "bytes"

func compareElement(a *SkipListElement, key []byte) int {
	if len(a.Key) == 0 {
		return -1
	}
	return bytes.Compare(a.Key, key)
}

func (node *SkipListElement) Reference() *SkipListElementReference {
	if node == nil {
		return nil
	}
	return &SkipListElementReference{
		ElementPointer: node.Id,
		Key:            node.Key,
	}
}

func (t *SkipList) saveElement(element *SkipListElement) error {
	if element == nil {
		return nil
	}
	return t.listStore.SaveElement(element.Id, element)
}

func (t *SkipList) deleteElement(element *SkipListElement) error {
	if element == nil {
		return nil
	}
	return t.listStore.DeleteElement(element.Id)
}

func (t *SkipList) loadElement(ref *SkipListElementReference) (*SkipListElement, error) {
	if ref.IsNil() {
		return nil, nil
	}
	return t.listStore.LoadElement(ref.ElementPointer)
}

func (ref *SkipListElementReference) IsNil() bool {
	if ref == nil {
		return true
	}
	if len(ref.Key) == 0 {
		return true
	}
	return false
}<|endoftext|>


<commit_before>package teams

import (
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

// How many random bytes are needed to create "Invite Key" token of
// chosen alphabet and length.
const SeitanRawIKeyLength = 10

// This is expected seitan token length, the secret "Invite Key" that
// is generated on one client and distributed to another via face-to-
// face meeting, use of a trusted courier etc.
//
// We only try to distinguish Seitan tokens from normal e-mail tokens
// via length so make sure they are never the same length. Right now
// server-trust e-mail tokens are 12 characters.
const SeitanEncodedIKeyLength = 16

// Key-Base 33 encoding. lower case letters except 'l' and digits except for '0' and '1'.
const KBase33EncodeStd = "abcdefghijkmnopqrstuvwxyz23456789"

var Base33Encoding = basex.NewEncoding(KBase33EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
// All following 3 structs should be considerd one. When any changes,
// Version in PEIKey has to be bumped up.
type SeitanPEIKey struct {
	_struct               bool `codec:",toarray"`
	Version               uint
	TeamKeyGeneration     keybase1.PerTeamKeyGeneration
	RandomNonce           keybase1.BoxNonce
	EncryptedIKeyAndLabel []byte // keybase1.SeitanIKeyAndLabel MsgPacked and encrypted
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base33Encoding.Encode(encodedKey[:], rawKey)

	var verify [SeitanRawIKeyLength]byte
	_, err = Base33Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !libkb.SecureByteArrayEq(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// GenerateIKeyFromString safely creates SeitanIKey value from
// plaintext string. Only length is checked - any 16-character token
// can be "Invite Key". Alphabet is not checked, as it is only a hint
// for token generation and it can change over time, but we assume
// that token length stays the same.
func GenerateIKeyFromString(token string) (ikey SeitanIKey, err error) {
	if len(token) != SeitanEncodedIKeyLength {
		return ikey, fmt.Errorf("invalid token length: expected %d characters, got %d", SeitanEncodedIKeyLength, len(token))
	}

	return SeitanIKey(token), nil
}

func (ikey SeitanIKey) String() string {
	return string(ikey)
}

const (
	SeitanScryptCost   = 1 << 10
	SeitanScryptR      = 8
	SeitanScryptP      = 1
	SeitanScryptKeylen = 32
)

// "Stretched Invite Key"
type SeitanSIKey [SeitanScryptKeylen]byte

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, SeitanScryptCost, SeitanScryptR, SeitanScryptP, SeitanScryptKeylen)
	if err != nil {
		return sikey, err
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) generatePackedEncryptedIKeyWithSecretKey(secretKey keybase1.Bytes32, gen keybase1.PerTeamKeyGeneration, nonce keybase1.BoxNonce, label keybase1.SeitanIKeyLabel) (peikey SeitanPEIKey, encoded string, err error) {
	var keyAndLabel keybase1.SeitanIKeyAndLabelVersion1
	keyAndLabel.I = keybase1.SeitanIKey(ikey)
	keyAndLabel.L = label

	packedKeyAndLabel, err := libkb.MsgpackEncode(keybase1.NewSeitanIKeyAndLabelWithV1(keyAndLabel))
	if err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = secretKey
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	encryptedIKeyAndLabel := secretbox.Seal(nil, []byte(packedKeyAndLabel), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:               1,
		TeamKeyGeneration:     gen,
		RandomNonce:           nonce,
		EncryptedIKeyAndLabel: encryptedIKeyAndLabel,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team, label keybase1.SeitanIKeyLabel) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	return ikey.generatePackedEncryptedIKeyWithSecretKey(appKey.Key, appKey.KeyGeneration, nonce, label)
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(&peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) decryptIKeyAndLabelWithSecretKey(secretKey keybase1.Bytes32) (ret keybase1.SeitanIKeyAndLabel, err error) {
	var encKey [libkb.NaclSecretBoxKeySize]byte = secretKey
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EncryptedIKeyAndLabel, &naclNonce, &encKey)
	if !ok {
		return ret, errors.New("failed to decrypt seitan plain")
	}

	err = libkb.MsgpackDecode(&ret, plain)
	if err != nil {
		return ret, err
	}

	return ret, nil
}

func (peikey SeitanPEIKey) DecryptIKeyAndLabel(ctx context.Context, team *Team) (ret keybase1.SeitanIKeyAndLabel, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ret, err
	}

	return peikey.decryptIKeyAndLabelWithSecretKey(appKey.Key)
}

// "Acceptance Key"
type SeitanAKey []byte

func (sikey SeitanSIKey) GenerateAcceptanceKey(uid keybase1.UID, eldestSeqno keybase1.Seqno, unixTime int64) (akey SeitanAKey, encoded string, err error) {
	type AKeyPayload struct {
		Stage       string         `codec:"stage" json:"stage"`
		UID         keybase1.UID   `codec:"uid" json:"uid"`
		EldestSeqno keybase1.Seqno `codec:"eldest_seqno" json:"eldest_seqno"`
		CTime       int64          `codec:"ctime" json:"ctime"`
	}

	payload, err := libkb.MsgpackEncode(AKeyPayload{
		Stage:       "accept",
		UID:         uid,
		EldestSeqno: eldestSeqno,
		CTime:       unixTime,
	})
	if err != nil {
		return akey, encoded, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return akey, encoded, err
	}

	out := mac.Sum(nil)
	akey = out[:32]
	encoded = base64.StdEncoding.EncodeToString(akey)
	return akey, encoded, nil
}
<commit_msg>don't use 'I' in the seitan token alphabet (#9794)<commit_after>package teams

import (
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

// How many random bytes are needed to create "Invite Key" token of
// chosen alphabet and length.
const SeitanRawIKeyLength = 10

// This is expected seitan token length, the secret "Invite Key" that
// is generated on one client and distributed to another via face-to-
// face meeting, use of a trusted courier etc.
//
// We only try to distinguish Seitan tokens from normal e-mail tokens
// via length so make sure they are never the same length. Right now
// server-trust e-mail tokens are 12 characters.
const SeitanEncodedIKeyLength = 16

// Key-Base 32 encoding. lower case letters except 'l', 'i' and digits except for '0' and '1'.
const KBase32EncodeStd = "abcdefghjkmnopqrstuvwxyz23456789"

var Base32Encoding = basex.NewEncoding(KBase32EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
// All following 3 structs should be considerd one. When any changes,
// Version in PEIKey has to be bumped up.
type SeitanPEIKey struct {
	_struct               bool `codec:",toarray"`
	Version               uint
	TeamKeyGeneration     keybase1.PerTeamKeyGeneration
	RandomNonce           keybase1.BoxNonce
	EncryptedIKeyAndLabel []byte // keybase1.SeitanIKeyAndLabel MsgPacked and encrypted
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base32Encoding.Encode(encodedKey[:], rawKey)

	var verify [SeitanRawIKeyLength]byte
	_, err = Base32Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !libkb.SecureByteArrayEq(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// GenerateIKeyFromString safely creates SeitanIKey value from
// plaintext string. Only length is checked - any 16-character token
// can be "Invite Key". Alphabet is not checked, as it is only a hint
// for token generation and it can change over time, but we assume
// that token length stays the same.
func GenerateIKeyFromString(token string) (ikey SeitanIKey, err error) {
	if len(token) != SeitanEncodedIKeyLength {
		return ikey, fmt.Errorf("invalid token length: expected %d characters, got %d", SeitanEncodedIKeyLength, len(token))
	}

	return SeitanIKey(token), nil
}

func (ikey SeitanIKey) String() string {
	return string(ikey)
}

const (
	SeitanScryptCost   = 1 << 10
	SeitanScryptR      = 8
	SeitanScryptP      = 1
	SeitanScryptKeylen = 32
)

// "Stretched Invite Key"
type SeitanSIKey [SeitanScryptKeylen]byte

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, SeitanScryptCost, SeitanScryptR, SeitanScryptP, SeitanScryptKeylen)
	if err != nil {
		return sikey, err
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) generatePackedEncryptedIKeyWithSecretKey(secretKey keybase1.Bytes32, gen keybase1.PerTeamKeyGeneration, nonce keybase1.BoxNonce, label keybase1.SeitanIKeyLabel) (peikey SeitanPEIKey, encoded string, err error) {
	var keyAndLabel keybase1.SeitanIKeyAndLabelVersion1
	keyAndLabel.I = keybase1.SeitanIKey(ikey)
	keyAndLabel.L = label

	packedKeyAndLabel, err := libkb.MsgpackEncode(keybase1.NewSeitanIKeyAndLabelWithV1(keyAndLabel))
	if err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = secretKey
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	encryptedIKeyAndLabel := secretbox.Seal(nil, []byte(packedKeyAndLabel), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:               1,
		TeamKeyGeneration:     gen,
		RandomNonce:           nonce,
		EncryptedIKeyAndLabel: encryptedIKeyAndLabel,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team, label keybase1.SeitanIKeyLabel) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	return ikey.generatePackedEncryptedIKeyWithSecretKey(appKey.Key, appKey.KeyGeneration, nonce, label)
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(&peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) decryptIKeyAndLabelWithSecretKey(secretKey keybase1.Bytes32) (ret keybase1.SeitanIKeyAndLabel, err error) {
	var encKey [libkb.NaclSecretBoxKeySize]byte = secretKey
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EncryptedIKeyAndLabel, &naclNonce, &encKey)
	if !ok {
		return ret, errors.New("failed to decrypt seitan plain")
	}

	err = libkb.MsgpackDecode(&ret, plain)
	if err != nil {
		return ret, err
	}

	return ret, nil
}

func (peikey SeitanPEIKey) DecryptIKeyAndLabel(ctx context.Context, team *Team) (ret keybase1.SeitanIKeyAndLabel, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ret, err
	}

	return peikey.decryptIKeyAndLabelWithSecretKey(appKey.Key)
}

// "Acceptance Key"
type SeitanAKey []byte

func (sikey SeitanSIKey) GenerateAcceptanceKey(uid keybase1.UID, eldestSeqno keybase1.Seqno, unixTime int64) (akey SeitanAKey, encoded string, err error) {
	type AKeyPayload struct {
		Stage       string         `codec:"stage" json:"stage"`
		UID         keybase1.UID   `codec:"uid" json:"uid"`
		EldestSeqno keybase1.Seqno `codec:"eldest_seqno" json:"eldest_seqno"`
		CTime       int64          `codec:"ctime" json:"ctime"`
	}

	payload, err := libkb.MsgpackEncode(AKeyPayload{
		Stage:       "accept",
		UID:         uid,
		EldestSeqno: eldestSeqno,
		CTime:       unixTime,
	})
	if err != nil {
		return akey, encoded, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return akey, encoded, err
	}

	out := mac.Sum(nil)
	akey = out[:32]
	encoded = base64.StdEncoding.EncodeToString(akey)
	return akey, encoded, nil
}
<|endoftext|>


<commit_before>package auth

import "github.com/micro/go-micro/v2/auth"

// SystemRules are the default rules which are applied to the runtime services
var SystemRules = map[string][]*auth.Resource{
	"*": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Generate"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Token"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Inspect"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.registry", Endpoint: "Registry.GetService"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.registry", Endpoint: "Registry.ListServices"},
	},
}
<commit_msg>Update default namespace requirement<commit_after>package auth

import "github.com/micro/go-micro/v2/auth"

// SystemRules are the default rules which are applied to the runtime services
var SystemRules = map[string][]*auth.Resource{
	"*": {
		&auth.Resource{Namespace: "*", Type: "*", Name: "*", Endpoint: "*"},
	},
	"": {
		&auth.Resource{Namespace: "*", Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Generate"},
		&auth.Resource{Namespace: "*", Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Token"},
		&auth.Resource{Namespace: "*", Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Inspect"},
		&auth.Resource{Namespace: "*", Type: "service", Name: "go.micro.registry", Endpoint: "Registry.GetService"},
		&auth.Resource{Namespace: "*", Type: "service", Name: "go.micro.registry", Endpoint: "Registry.ListServices"},
	},
}
<|endoftext|>


<commit_before>package controllers

import (
	"io/ioutil"
	"encoding/json"
	"net/http"
	"github.com/gorilla/mux"
	"github.com/beeker1121/resounden/api/v1/utils"
	"github.com/beeker1121/resounden/api/v1/models"
)

type PlaylistController struct {
	APIKey string
}

func NewPlaylistController(apiKey string) *PlaylistController {
	return &PlaylistController{apiKey}
}

func (p *PlaylistController) Register(router *mux.Router) {
	router.HandleFunc("/api/v1/playlist/", p.getPlaylist)
	router.HandleFunc("/api/v1/playlist/{username}", p.getPlaylist)
}

func (p *PlaylistController) getPlaylist(w http.ResponseWriter, r *http.Request) {
	// Get the request variables
	vars := mux.Vars(r)

	// If the next_href param was passed to us, use that for the URL
	nextHref := r.URL.Query().Get("next_href")

	if nextHref == "" {
		nextHref = "http://api.soundcloud.com/users/" + vars["username"] + "/favorites?client_id=" + p.APIKey + "&linked_partitioning=1"
	}

	// Call the Soundcloud API
	resp, err := http.Get(nextHref)
	defer resp.Body.Close()
	if err != nil {
		utils.WriteError(utils.Error{404, "User not found"}, w)
		return
	}

	// Store the body of the response, using ioutil since it's a stream
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		utils.WriteError(utils.Error{500, "Internal server error"}, w)
		return
	}

	// Check for an error response first
	var jsonError utils.Errors

	// If we can't decode this json into our Errors struct type
	if err := json.Unmarshal(body, &jsonError); err != nil || len(jsonError.Errors) <= 0 {
		// Try decoding it into our Collection type
		var collection models.Collection

		// If we can't decode this json into our struct type
		if err := json.Unmarshal(body, &collection); err != nil {
			utils.WriteError(utils.Error{500, "Can't decode JSON into struct type"}, w)
			return
		}

		// Append the Soundcloud Client ID to stream_url for each track
		for i, _ := range collection.Collection {
			collection.Collection[i].StreamURL += "?client_id=" + p.APIKey
		}

		// Encode our Collection struct as a json string and send
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(collection)

		return
	}

	// Otherwise output the error
	utils.WriteError(utils.Error{404, "Member could not be found"}, w)
}<commit_msg>Restructured jsonError handling in playlist API controller<commit_after>package controllers

import (
	"io/ioutil"
	"encoding/json"
	"net/http"
	"github.com/gorilla/mux"
	"github.com/beeker1121/resounden/api/v1/utils"
	"github.com/beeker1121/resounden/api/v1/models"
)

type PlaylistController struct {
	APIKey string
}

func NewPlaylistController(apiKey string) *PlaylistController {
	return &PlaylistController{apiKey}
}

func (p *PlaylistController) Register(router *mux.Router) {
	router.HandleFunc("/api/v1/playlist/", p.getPlaylist)
	router.HandleFunc("/api/v1/playlist/{username}", p.getPlaylist)
}

func (p *PlaylistController) getPlaylist(w http.ResponseWriter, r *http.Request) {
	// Get the request variables
	vars := mux.Vars(r)

	// If the next_href param was passed to us, use that for the URL
	nextHref := r.URL.Query().Get("next_href")

	if nextHref == "" {
		nextHref = "http://api.soundcloud.com/users/" + vars["username"] + "/favorites?client_id=" + p.APIKey + "&linked_partitioning=1"
	}

	// Call the Soundcloud API
	resp, err := http.Get(nextHref)
	defer resp.Body.Close()
	if err != nil {
		utils.WriteError(utils.Error{404, "User not found"}, w)
		return
	}

	// Store the body of the response, using ioutil since it's a stream
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		utils.WriteError(utils.Error{500, "Internal server error"}, w)
		return
	}

	// Check for an error response first
	var jsonError utils.Errors

	// If we can decode this json into our Errors struct type
	if json.Unmarshal(body, &jsonError); len(jsonError.Errors) > 0 {
		utils.WriteError(utils.Error{404, "Member could not be found"}, w)
		return
	}

	// Try decoding it into our Collection type
	var collection models.Collection

	// If we can't decode this json into our struct type
	if err := json.Unmarshal(body, &collection); err != nil {
		utils.WriteError(utils.Error{500, "Can't decode JSON into struct type"}, w)
		return
	}

	// Append the Soundcloud Client ID to stream_url for each track
	for i, _ := range collection.Collection {
		collection.Collection[i].StreamURL += "?client_id=" + p.APIKey
	}

	// Encode our Collection struct as a json string and send
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(collection)
}<|endoftext|>


<commit_before>package context

import (
	"os"
	"testing"
)

func TestWatcherLaunch(t *testing.T) {
	wd := os.Getenv("GOPATH") + "/src/github.com/yosssi/goat/test/context/TestWatcherLaunch001"
	os.Chdir(wd)
	ctx, err := NewContext(500)
	if err != nil {
		t.Errorf("Error (%s) occurred.", err.Error())
	}
	if ctx.Config == nil || len(ctx.Config.Watchers) != 1 {
		t.Error("Context is invalid.")
	}
	watcher := ctx.Config.Watchers[0]
	if watcher == nil {
		t.Error("Watcher is invalid.")
	}
	watcher.Launch(ctx, make(chan Job))
}
<commit_msg>Updated context/watcher_test.go.<commit_after>package context
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 pally is a simple, atomic-based metrics library. It interoperates
// seamlessly with both Prometheus and Tally, providing ready-to-use Prometheus
// text and Protocol Buffer endpoints, differential updates to StatsD- or
// M3-based systems, and excellent performance along the hot path.
//
// Metric Names
//
// Pally requires that all metric names, label names, and label values be valid
// both in Tally and in Prometheus. Metric and label names must pass
// IsValidName. Statically-defined label values must pass IsValidLabelValue,
// but dynamic label values are automatically scrubbed using ScrubLabelValue.
// This minimizes magic while still permitting use of label values generated at
// runtime (e.g., service names).
//
// Counters And Gauges
//
// Pally offers two simple metric types: counters and gauges. Counters
// represent an ever-accumulating total, like a car's odometer. Gauges
// represent a point-in-time measurement, like a car's speedometer. In Pally,
// both counters and gauges must have all their labels specified ahead of time.
//
// Vectors
//
// In many real-world situations, it's impossible to know all the labels for a
// metric ahead of time. For example, you may want to track the number of
// requests your server receives by caller; in most cases, you can't list all
// the possible callers ahead of time. To accommadate these situations, Pally
// offers vectors.
//
// Vectors represent a collection of metrics that have some constant labels,
// but some labels assigned at runtime. At vector construction time, you must
// specify the variable label keys; in our example, we'd supply "caller_name"
// as the only variable label. At runtime, pass the values for the variable
// labels to the Get (or MustGet) method on the vector. The number of label
// values must match the configured number of label keys, and they must be
// supplied in the same order. Vectors create metrics on demand, caching them
// for efficient repeated access.
//
//   registry := NewRegistry()
//   requestsByCaller := registry.NewCounterVector(Opts{
//     Name: "requests",
//     Help: "Total requests by caller name.",
//     ConstLabels: Labels{
//       "zone": "us-west-1",
//       "service": "my_service_name",
//     },
//     // At runtime, we'll supply the caller name.
//     VariableLabels: []string{"caller_name"},
//   })
//   // In real-world use, we'd do this in a handler function (and we'd
//   // probably use the safer Get variant).
//   vec.MustGet("some_calling_service").Inc()
//
package pally
<commit_msg>Untypo the typo that was previously another typo. (#1274)<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 pally is a simple, atomic-based metrics library. It interoperates
// seamlessly with both Prometheus and Tally, providing ready-to-use Prometheus
// text and Protocol Buffer endpoints, differential updates to StatsD- or
// M3-based systems, and excellent performance along the hot path.
//
// Metric Names
//
// Pally requires that all metric names, label names, and label values be valid
// both in Tally and in Prometheus. Metric and label names must pass
// IsValidName. Statically-defined label values must pass IsValidLabelValue,
// but dynamic label values are automatically scrubbed using ScrubLabelValue.
// This minimizes magic while still permitting use of label values generated at
// runtime (e.g., service names).
//
// Counters And Gauges
//
// Pally offers two simple metric types: counters and gauges. Counters
// represent an ever-accumulating total, like a car's odometer. Gauges
// represent a point-in-time measurement, like a car's speedometer. In Pally,
// both counters and gauges must have all their labels specified ahead of time.
//
// Vectors
//
// In many real-world situations, it's impossible to know all the labels for a
// metric ahead of time. For example, you may want to track the number of
// requests your server receives by caller; in most cases, you can't list all
// the possible callers ahead of time. To accommodate these situations, Pally
// offers vectors.
//
// Vectors represent a collection of metrics that have some constant labels,
// but some labels assigned at runtime. At vector construction time, you must
// specify the variable label keys; in our example, we'd supply "caller_name"
// as the only variable label. At runtime, pass the values for the variable
// labels to the Get (or MustGet) method on the vector. The number of label
// values must match the configured number of label keys, and they must be
// supplied in the same order. Vectors create metrics on demand, caching them
// for efficient repeated access.
//
//   registry := NewRegistry()
//   requestsByCaller := registry.NewCounterVector(Opts{
//     Name: "requests",
//     Help: "Total requests by caller name.",
//     ConstLabels: Labels{
//       "zone": "us-west-1",
//       "service": "my_service_name",
//     },
//     // At runtime, we'll supply the caller name.
//     VariableLabels: []string{"caller_name"},
//   })
//   // In real-world use, we'd do this in a handler function (and we'd
//   // probably use the safer Get variant).
//   vec.MustGet("some_calling_service").Inc()
//
package pally
<|endoftext|>


<commit_before>package jsoniter

import (
	"io"
	"bytes"
)

// Unmarshal adapts to json/encoding APIs
func Unmarshal(data []byte, v interface{}) error {
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	iter.ReadVal(v)
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return nil
	}
	if iter.Error == nil {
		iter.reportError("Unmarshal", "there are bytes left after unmarshal")
	}
	return iter.Error
}

func UnmarshalAny(data []byte) (Any, error) {
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	any := iter.ReadAny()
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return any, nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
	}
	return any, iter.Error
}

func lastNotSpacePos(data []byte) int {
	for i := len(data) - 1; i >= 0; i-- {
		if data[i] != ' ' && data[i] != '\t' && data[i] != '\r' && data[i] != '\n' {
			return i + 1
		}
	}
	return 0
}

func UnmarshalFromString(str string, v interface{}) error {
	data := []byte(str)
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	iter.ReadVal(v)
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
	}
	return iter.Error
}

func UnmarshalAnyFromString(str string) (Any, error) {
	data := []byte(str)
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	any := iter.ReadAny()
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return any, nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalAnyFromString", "there are bytes left after unmarshal")
	}
	return nil, iter.Error
}

// jsoniterator.Marshal is an adapter to json.Marshal
//
// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API

func Marshal(v interface{}) ([]byte, error) {
	buf := &bytes.Buffer{}
	stream := NewStream(buf, 512)
	stream.WriteVal(v)
	stream.Flush()
	if stream.Error != nil {
		return nil, stream.Error
	}
	return buf.Bytes(), nil
}

func MarshalToString(v interface{}) (string, error) {
	buf, err := Marshal(v)
	if err != nil {
		return "", err
	}
	return string(buf), nil
}

func NewDecoder(reader io.Reader) *AdaptedDecoder {
	iter := Parse(reader, 512)
	return &AdaptedDecoder{iter}
}

type AdaptedDecoder struct {
	iter *Iterator
}

func (adapter *AdaptedDecoder) Decode(obj interface{}) error {
	adapter.iter.ReadVal(obj)
	err := adapter.iter.Error
	if err == io.EOF {
		return nil
	}
	return adapter.iter.Error
}

func (adapter *AdaptedDecoder) More() bool {
	return adapter.iter.head != adapter.iter.tail
}

func (adapter *AdaptedDecoder) Buffered() io.Reader {
	remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail]
	return bytes.NewReader(remaining)
}

func NewEncoder(writer io.Writer) *AdaptedEncoder {
	stream := NewStream(writer, 512)
	return &AdaptedEncoder{stream}
}

type AdaptedEncoder struct {
	stream *Stream
}

func (adapter *AdaptedEncoder) Encode(val interface{}) error {
	adapter.stream.WriteVal(val)
	adapter.stream.Flush()
	return adapter.stream.Error
}

func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) {
	// not implemented yet
}<commit_msg>Marshal comment<commit_after>package jsoniter

import (
	"io"
	"bytes"
)

// Unmarshal adapts to json/encoding APIs
func Unmarshal(data []byte, v interface{}) error {
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	iter.ReadVal(v)
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return nil
	}
	if iter.Error == nil {
		iter.reportError("Unmarshal", "there are bytes left after unmarshal")
	}
	return iter.Error
}

func UnmarshalAny(data []byte) (Any, error) {
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	any := iter.ReadAny()
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return any, nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
	}
	return any, iter.Error
}

func lastNotSpacePos(data []byte) int {
	for i := len(data) - 1; i >= 0; i-- {
		if data[i] != ' ' && data[i] != '\t' && data[i] != '\r' && data[i] != '\n' {
			return i + 1
		}
	}
	return 0
}

func UnmarshalFromString(str string, v interface{}) error {
	data := []byte(str)
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	iter.ReadVal(v)
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
	}
	return iter.Error
}

func UnmarshalAnyFromString(str string) (Any, error) {
	data := []byte(str)
	data = data[:lastNotSpacePos(data)]
	iter := ParseBytes(data)
	any := iter.ReadAny()
	if iter.head == iter.tail {
		iter.loadMore()
	}
	if iter.Error == io.EOF {
		return any, nil
	}
	if iter.Error == nil {
		iter.reportError("UnmarshalAnyFromString", "there are bytes left after unmarshal")
	}
	return nil, iter.Error
}

// jsoniterator.Marshal is an adapter to json.Marshal
//
// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API
func Marshal(v interface{}) ([]byte, error) {
	buf := &bytes.Buffer{}
	stream := NewStream(buf, 512)
	stream.WriteVal(v)
	stream.Flush()
	if stream.Error != nil {
		return nil, stream.Error
	}
	return buf.Bytes(), nil
}

func MarshalToString(v interface{}) (string, error) {
	buf, err := Marshal(v)
	if err != nil {
		return "", err
	}
	return string(buf), nil
}

func NewDecoder(reader io.Reader) *AdaptedDecoder {
	iter := Parse(reader, 512)
	return &AdaptedDecoder{iter}
}

type AdaptedDecoder struct {
	iter *Iterator
}

func (adapter *AdaptedDecoder) Decode(obj interface{}) error {
	adapter.iter.ReadVal(obj)
	err := adapter.iter.Error
	if err == io.EOF {
		return nil
	}
	return adapter.iter.Error
}

func (adapter *AdaptedDecoder) More() bool {
	return adapter.iter.head != adapter.iter.tail
}

func (adapter *AdaptedDecoder) Buffered() io.Reader {
	remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail]
	return bytes.NewReader(remaining)
}

func NewEncoder(writer io.Writer) *AdaptedEncoder {
	stream := NewStream(writer, 512)
	return &AdaptedEncoder{stream}
}

type AdaptedEncoder struct {
	stream *Stream
}

func (adapter *AdaptedEncoder) Encode(val interface{}) error {
	adapter.stream.WriteVal(val)
	adapter.stream.Flush()
	return adapter.stream.Error
}

func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) {
	// not implemented yet
}<|endoftext|>


<commit_before>package orm

import "gopkg.in/mgo.v2/bson"
import "github.com/lfq7413/tomato/utils"
import "strings"

var clpValidKeys = []string{"find", "get", "create", "update", "delete", "addField"}
var defaultClassLevelPermissions bson.M
var defaultColumns map[string]bson.M

func init() {
	defaultClassLevelPermissions = bson.M{}
	for _, v := range clpValidKeys {
		defaultClassLevelPermissions[v] = bson.M{
			"*": true,
		}
	}
	defaultColumns = map[string]bson.M{
		"_Default": bson.M{
			"objectId":  bson.M{"type": "String"},
			"createdAt": bson.M{"type": "Date"},
			"updatedAt": bson.M{"type": "Date"},
			"ACL":       bson.M{"type": "ACL"},
		},
		"_User": bson.M{
			"username":      bson.M{"type": "String"},
			"password":      bson.M{"type": "String"},
			"authData":      bson.M{"type": "Object"},
			"email":         bson.M{"type": "String"},
			"emailVerified": bson.M{"type": "Boolean"},
		},
		"_Installation": bson.M{
			"installationId":   bson.M{"type": "String"},
			"deviceToken":      bson.M{"type": "String"},
			"channels":         bson.M{"type": "Array"},
			"deviceType":       bson.M{"type": "String"},
			"pushType":         bson.M{"type": "String"},
			"GCMSenderId":      bson.M{"type": "String"},
			"timeZone":         bson.M{"type": "String"},
			"localeIdentifier": bson.M{"type": "String"},
			"badge":            bson.M{"type": "Number"},
		},
		"_Role": bson.M{
			"name":  bson.M{"type": "String"},
			"users": bson.M{"type": "Relation", "targetClass": "_User"},
			"roles": bson.M{"type": "Relation", "targetClass": "_Role"},
		},
		"_Session": bson.M{
			"restricted":     bson.M{"type": "Boolean"},
			"user":           bson.M{"type": "Pointer", "targetClass": "_User"},
			"installationId": bson.M{"type": "String"},
			"sessionToken":   bson.M{"type": "String"},
			"expiresAt":      bson.M{"type": "Date"},
			"createdWith":    bson.M{"type": "Object"},
		},
		"_Product": bson.M{
			"productIdentifier": bson.M{"type": "String"},
			"download":          bson.M{"type": "File"},
			"downloadName":      bson.M{"type": "String"},
			"icon":              bson.M{"type": "File"},
			"order":             bson.M{"type": "Number"},
			"title":             bson.M{"type": "String"},
			"subtitle":          bson.M{"type": "String"},
		},
	}
}

// Schema ...
type Schema struct {
	collection *MongoSchemaCollection
	data       bson.M
	perms      bson.M
}

// AddClassIfNotExists 添加类定义
func (s *Schema) AddClassIfNotExists(className string, fields bson.M, classLevelPermissions bson.M) bson.M {
	// TODO
	if s.data[className] != nil {
		// TODO 类已存在
		return nil
	}

	mongoObject := mongoSchemaFromFieldsAndClassNameAndCLP(fields, className, classLevelPermissions)
	if mongoObject["result"] == nil {
		// TODO 转换出现问题
		return nil
	}
	err := s.collection.addSchema(className, utils.MapInterface(mongoObject["result"]))
	if err != nil {
		// TODO 出现错误
		return nil
	}

	return utils.MapInterface(mongoObject["result"])
}

func (s *Schema) reloadData() {
	// TODO
	s.data = bson.M{}
	s.perms = bson.M{}
	results, err := s.collection.GetAllSchemas()
	if err != nil {
		return
	}
	for _, obj := range results {
		className := ""
		classData := bson.M{}
		var permsData interface{}

		for k, v := range obj {
			switch k {
			case "_id":
				className = utils.String(v)
			case "_metadata":
				if v != nil && utils.MapInterface(v) != nil && utils.MapInterface(v)["class_permissions"] != nil {
					permsData = utils.MapInterface(v)["class_permissions"]
				}
			default:
				classData[k] = v
			}
		}

		if className != "" {
			s.data[className] = classData
			if permsData != nil {
				s.perms[className] = permsData
			}
		}
	}
}

// MongoSchemaToSchemaAPIResponse ...
func MongoSchemaToSchemaAPIResponse(schema bson.M) bson.M {
	result := bson.M{
		"className": schema["_id"],
		"fields":    mongoSchemaAPIResponseFields(schema),
	}

	classLevelPermissions := utils.CopyMap(defaultClassLevelPermissions)
	if schema["_metadata"] != nil && utils.MapInterface(schema["_metadata"]) != nil {
		metadata := utils.MapInterface(schema["_metadata"])
		if metadata["class_permissions"] != nil && utils.MapInterface(metadata["class_permissions"]) != nil {
			classPermissions := utils.MapInterface(metadata["class_permissions"])
			for k, v := range classPermissions {
				classLevelPermissions[k] = v
			}
		}
	}
	result["classLevelPermissions"] = classLevelPermissions

	return result
}

var nonFieldSchemaKeys = []string{"_id", "_metadata", "_client_permissions"}

func mongoSchemaAPIResponseFields(schema bson.M) bson.M {
	fieldNames := []string{}
	for k := range schema {
		t := false
		for _, v := range nonFieldSchemaKeys {
			if k == v {
				t = true
				break
			}
		}
		if t == false {
			fieldNames = append(fieldNames, k)
		}
	}
	response := bson.M{}
	for _, v := range fieldNames {
		response[v] = mongoFieldTypeToSchemaAPIType(utils.String(schema[v]))
	}
	response["ACL"] = bson.M{
		"type": "ACL",
	}
	response["createdAt"] = bson.M{
		"type": "Date",
	}
	response["updatedAt"] = bson.M{
		"type": "Date",
	}
	response["objectId"] = bson.M{
		"type": "String",
	}
	return response
}

func mongoFieldTypeToSchemaAPIType(t string) bson.M {
	if t[0] == '*' {
		return bson.M{
			"type":        "Pointer",
			"targetClass": string(t[1:]),
		}
	}
	if strings.HasPrefix(t, "relation<") {
		return bson.M{
			"type":        "Relation",
			"targetClass": string(t[len("relation<") : len(t)-1]),
		}
	}
	switch t {
	case "number":
		return bson.M{
			"type": "Number",
		}
	case "string":
		return bson.M{
			"type": "String",
		}
	case "boolean":
		return bson.M{
			"type": "Boolean",
		}
	case "date":
		return bson.M{
			"type": "Date",
		}
	case "map":
		return bson.M{
			"type": "Object",
		}
	case "object":
		return bson.M{
			"type": "Object",
		}
	case "array":
		return bson.M{
			"type": "Array",
		}
	case "geopoint":
		return bson.M{
			"type": "GeoPoint",
		}
	case "file":
		return bson.M{
			"type": "File",
		}
	}

	return bson.M{}
}

func mongoSchemaFromFieldsAndClassNameAndCLP(fields bson.M, className string, classLevelPermissions bson.M) bson.M {
	if classNameIsValid(className) == false {
		// TODO 无效类名
		return nil
	}
	for fieldName := range fields {
		if fieldNameIsValid(fieldName) == false {
			// TODO 无效字段名
			return nil
		}
		if fieldNameIsValidForClass(fieldName, className) == false {
			// TODO 无法添加字段
			return nil
		}
	}

	mongoObject := bson.M{
		"_id":       className,
		"objectId":  "string",
		"updatedAt": "string",
		"createdAt": "string",
	}

	if defaultColumns[className] != nil {
		for fieldName := range defaultColumns[className] {
			validatedField := schemaAPITypeToMongoFieldType(utils.MapInterface(defaultColumns[className][fieldName]))
			if validatedField["result"] == nil {
				// TODO 转换错误
				return nil
			}
			mongoObject[fieldName] = validatedField["result"]
		}
	}

	for fieldName := range fields {
		validatedField := schemaAPITypeToMongoFieldType(utils.MapInterface(defaultColumns[className][fieldName]))
		if validatedField["result"] == nil {
			// TODO 转换错误
			return nil
		}
		mongoObject[fieldName] = validatedField["result"]
	}

	geoPoints := []string{}
	for k, v := range mongoObject {
		if utils.String(v) == "geopoint" {
			geoPoints = append(geoPoints, k)
		}
	}
	if len(geoPoints) > 1 {
		// TODO 只能有一个 geoPoint
		return nil
	}

	validateCLP(classLevelPermissions)
	var metadata bson.M
	if mongoObject["_metadata"] == nil && utils.MapInterface(mongoObject["_metadata"]) == nil {
		metadata = bson.M{}
	} else {
		metadata = utils.MapInterface(mongoObject["_metadata"])
	}
	if classLevelPermissions == nil {
		delete(metadata, "class_permissions")
	} else {
		metadata["class_permissions"] = classLevelPermissions
	}
	mongoObject["_metadata"] = metadata

	return bson.M{
		"result": mongoObject,
	}
}

func classNameIsValid(className string) bool {
	return false
}

func fieldNameIsValid(fieldName string) bool {
	return false
}

func fieldNameIsValidForClass(fieldName string, className string) bool {
	return false
}

func schemaAPITypeToMongoFieldType(t bson.M) bson.M {
	return nil
}

func validateCLP(classLevelPermissions bson.M) {

}

// Load 返回一个新的 Schema 结构体
func Load(collection *MongoSchemaCollection) *Schema {
	schema := &Schema{
		collection: collection,
	}
	schema.reloadData()
	return schema
}
<commit_msg>完成类名校验部分<commit_after>package orm

import (
	"regexp"

	"gopkg.in/mgo.v2/bson"
)
import "github.com/lfq7413/tomato/utils"
import "strings"

var clpValidKeys = []string{"find", "get", "create", "update", "delete", "addField"}
var defaultClassLevelPermissions bson.M
var defaultColumns map[string]bson.M

func init() {
	defaultClassLevelPermissions = bson.M{}
	for _, v := range clpValidKeys {
		defaultClassLevelPermissions[v] = bson.M{
			"*": true,
		}
	}
	defaultColumns = map[string]bson.M{
		"_Default": bson.M{
			"objectId":  bson.M{"type": "String"},
			"createdAt": bson.M{"type": "Date"},
			"updatedAt": bson.M{"type": "Date"},
			"ACL":       bson.M{"type": "ACL"},
		},
		"_User": bson.M{
			"username":      bson.M{"type": "String"},
			"password":      bson.M{"type": "String"},
			"authData":      bson.M{"type": "Object"},
			"email":         bson.M{"type": "String"},
			"emailVerified": bson.M{"type": "Boolean"},
		},
		"_Installation": bson.M{
			"installationId":   bson.M{"type": "String"},
			"deviceToken":      bson.M{"type": "String"},
			"channels":         bson.M{"type": "Array"},
			"deviceType":       bson.M{"type": "String"},
			"pushType":         bson.M{"type": "String"},
			"GCMSenderId":      bson.M{"type": "String"},
			"timeZone":         bson.M{"type": "String"},
			"localeIdentifier": bson.M{"type": "String"},
			"badge":            bson.M{"type": "Number"},
		},
		"_Role": bson.M{
			"name":  bson.M{"type": "String"},
			"users": bson.M{"type": "Relation", "targetClass": "_User"},
			"roles": bson.M{"type": "Relation", "targetClass": "_Role"},
		},
		"_Session": bson.M{
			"restricted":     bson.M{"type": "Boolean"},
			"user":           bson.M{"type": "Pointer", "targetClass": "_User"},
			"installationId": bson.M{"type": "String"},
			"sessionToken":   bson.M{"type": "String"},
			"expiresAt":      bson.M{"type": "Date"},
			"createdWith":    bson.M{"type": "Object"},
		},
		"_Product": bson.M{
			"productIdentifier": bson.M{"type": "String"},
			"download":          bson.M{"type": "File"},
			"downloadName":      bson.M{"type": "String"},
			"icon":              bson.M{"type": "File"},
			"order":             bson.M{"type": "Number"},
			"title":             bson.M{"type": "String"},
			"subtitle":          bson.M{"type": "String"},
		},
	}
}

// Schema ...
type Schema struct {
	collection *MongoSchemaCollection
	data       bson.M
	perms      bson.M
}

// AddClassIfNotExists 添加类定义
func (s *Schema) AddClassIfNotExists(className string, fields bson.M, classLevelPermissions bson.M) bson.M {
	// TODO
	if s.data[className] != nil {
		// TODO 类已存在
		return nil
	}

	mongoObject := mongoSchemaFromFieldsAndClassNameAndCLP(fields, className, classLevelPermissions)
	if mongoObject["result"] == nil {
		// TODO 转换出现问题
		return nil
	}
	err := s.collection.addSchema(className, utils.MapInterface(mongoObject["result"]))
	if err != nil {
		// TODO 出现错误
		return nil
	}

	return utils.MapInterface(mongoObject["result"])
}

func (s *Schema) reloadData() {
	// TODO
	s.data = bson.M{}
	s.perms = bson.M{}
	results, err := s.collection.GetAllSchemas()
	if err != nil {
		return
	}
	for _, obj := range results {
		className := ""
		classData := bson.M{}
		var permsData interface{}

		for k, v := range obj {
			switch k {
			case "_id":
				className = utils.String(v)
			case "_metadata":
				if v != nil && utils.MapInterface(v) != nil && utils.MapInterface(v)["class_permissions"] != nil {
					permsData = utils.MapInterface(v)["class_permissions"]
				}
			default:
				classData[k] = v
			}
		}

		if className != "" {
			s.data[className] = classData
			if permsData != nil {
				s.perms[className] = permsData
			}
		}
	}
}

// MongoSchemaToSchemaAPIResponse ...
func MongoSchemaToSchemaAPIResponse(schema bson.M) bson.M {
	result := bson.M{
		"className": schema["_id"],
		"fields":    mongoSchemaAPIResponseFields(schema),
	}

	classLevelPermissions := utils.CopyMap(defaultClassLevelPermissions)
	if schema["_metadata"] != nil && utils.MapInterface(schema["_metadata"]) != nil {
		metadata := utils.MapInterface(schema["_metadata"])
		if metadata["class_permissions"] != nil && utils.MapInterface(metadata["class_permissions"]) != nil {
			classPermissions := utils.MapInterface(metadata["class_permissions"])
			for k, v := range classPermissions {
				classLevelPermissions[k] = v
			}
		}
	}
	result["classLevelPermissions"] = classLevelPermissions

	return result
}

var nonFieldSchemaKeys = []string{"_id", "_metadata", "_client_permissions"}

func mongoSchemaAPIResponseFields(schema bson.M) bson.M {
	fieldNames := []string{}
	for k := range schema {
		t := false
		for _, v := range nonFieldSchemaKeys {
			if k == v {
				t = true
				break
			}
		}
		if t == false {
			fieldNames = append(fieldNames, k)
		}
	}
	response := bson.M{}
	for _, v := range fieldNames {
		response[v] = mongoFieldTypeToSchemaAPIType(utils.String(schema[v]))
	}
	response["ACL"] = bson.M{
		"type": "ACL",
	}
	response["createdAt"] = bson.M{
		"type": "Date",
	}
	response["updatedAt"] = bson.M{
		"type": "Date",
	}
	response["objectId"] = bson.M{
		"type": "String",
	}
	return response
}

func mongoFieldTypeToSchemaAPIType(t string) bson.M {
	if t[0] == '*' {
		return bson.M{
			"type":        "Pointer",
			"targetClass": string(t[1:]),
		}
	}
	if strings.HasPrefix(t, "relation<") {
		return bson.M{
			"type":        "Relation",
			"targetClass": string(t[len("relation<") : len(t)-1]),
		}
	}
	switch t {
	case "number":
		return bson.M{
			"type": "Number",
		}
	case "string":
		return bson.M{
			"type": "String",
		}
	case "boolean":
		return bson.M{
			"type": "Boolean",
		}
	case "date":
		return bson.M{
			"type": "Date",
		}
	case "map":
		return bson.M{
			"type": "Object",
		}
	case "object":
		return bson.M{
			"type": "Object",
		}
	case "array":
		return bson.M{
			"type": "Array",
		}
	case "geopoint":
		return bson.M{
			"type": "GeoPoint",
		}
	case "file":
		return bson.M{
			"type": "File",
		}
	}

	return bson.M{}
}

func mongoSchemaFromFieldsAndClassNameAndCLP(fields bson.M, className string, classLevelPermissions bson.M) bson.M {
	if classNameIsValid(className) == false {
		// TODO 无效类名
		return nil
	}
	for fieldName := range fields {
		if fieldNameIsValid(fieldName) == false {
			// TODO 无效字段名
			return nil
		}
		if fieldNameIsValidForClass(fieldName, className) == false {
			// TODO 无法添加字段
			return nil
		}
	}

	mongoObject := bson.M{
		"_id":       className,
		"objectId":  "string",
		"updatedAt": "string",
		"createdAt": "string",
	}

	if defaultColumns[className] != nil {
		for fieldName := range defaultColumns[className] {
			validatedField := schemaAPITypeToMongoFieldType(utils.MapInterface(defaultColumns[className][fieldName]))
			if validatedField["result"] == nil {
				// TODO 转换错误
				return nil
			}
			mongoObject[fieldName] = validatedField["result"]
		}
	}

	for fieldName := range fields {
		validatedField := schemaAPITypeToMongoFieldType(utils.MapInterface(defaultColumns[className][fieldName]))
		if validatedField["result"] == nil {
			// TODO 转换错误
			return nil
		}
		mongoObject[fieldName] = validatedField["result"]
	}

	geoPoints := []string{}
	for k, v := range mongoObject {
		if utils.String(v) == "geopoint" {
			geoPoints = append(geoPoints, k)
		}
	}
	if len(geoPoints) > 1 {
		// TODO 只能有一个 geoPoint
		return nil
	}

	validateCLP(classLevelPermissions)
	var metadata bson.M
	if mongoObject["_metadata"] == nil && utils.MapInterface(mongoObject["_metadata"]) == nil {
		metadata = bson.M{}
	} else {
		metadata = utils.MapInterface(mongoObject["_metadata"])
	}
	if classLevelPermissions == nil {
		delete(metadata, "class_permissions")
	} else {
		metadata["class_permissions"] = classLevelPermissions
	}
	mongoObject["_metadata"] = metadata

	return bson.M{
		"result": mongoObject,
	}
}

func classNameIsValid(className string) bool {
	return className == "_User" ||
		className == "_Installation" ||
		className == "_Session" ||
		className == "_Role" ||
		className == "_Product" ||
		joinClassIsValid(className) ||
		fieldNameIsValid(className)
}

var joinClassRegex = `^_Join:[A-Za-z0-9_]+:[A-Za-z0-9_]+`

func joinClassIsValid(className string) bool {
	b, _ := regexp.MatchString(joinClassRegex, className)
	return b
}

var classAndFieldRegex = `^[A-Za-z][A-Za-z0-9_]*$`

func fieldNameIsValid(fieldName string) bool {
	b, _ := regexp.MatchString(classAndFieldRegex, fieldName)
	return b
}

func fieldNameIsValidForClass(fieldName string, className string) bool {
	return false
}

func schemaAPITypeToMongoFieldType(t bson.M) bson.M {
	return nil
}

func validateCLP(classLevelPermissions bson.M) {

}

// Load 返回一个新的 Schema 结构体
func Load(collection *MongoSchemaCollection) *Schema {
	schema := &Schema{
		collection: collection,
	}
	schema.reloadData()
	return schema
}
<|endoftext|>