<commit_before>package redis

import (
	"bytes"
	"encoding/gob"
	"reflect"
	"time"

	"cloud.google.com/go/datastore"
	"github.com/acoshift/ds"
	"github.com/garyburd/redigo/redis"
)

// Cache implement Cache interface
type Cache struct {
	Pool   *redis.Pool
	Prefix string
	TTL    time.Duration
	Skip   func(*datastore.Key) bool
}

func encode(v interface{}) ([]byte, error) {
	w := &bytes.Buffer{}
	err := gob.NewEncoder(w).Encode(v)
	if err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}

func decode(b []byte, v interface{}) error {
	return gob.NewDecoder(bytes.NewReader(b)).Decode(v)
}

// Get gets data
func (cache *Cache) Get(key *datastore.Key, dst interface{}) error {
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := redis.Bytes(db.Do("GET", cache.Prefix+key.String()))
	if err != nil {
		return err
	}
	if len(b) == 0 {
		return ds.ErrCacheNotFound
	}
	return decode(b, dst)
}

// GetMulti gets multi data
func (cache *Cache) GetMulti(keys []*datastore.Key, dst interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	for _, key := range keys {
		db.Send("GET", cache.Prefix+key.String())
	}
	err := db.Flush()
	if err != nil {
		return err
	}
	for i := range keys {
		b, err := redis.Bytes(db.Receive())
		if err != nil {
			return err
		}
		if len(b) > 0 {
			decode(b, reflect.Indirect(reflect.ValueOf(dst)).Index(i).Interface())
		}
	}
	return nil
}

// Set sets data
func (cache *Cache) Set(key *datastore.Key, src interface{}) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := encode(src)
	if err != nil {
		return err
	}
	if cache.TTL > 0 {
		_, err = db.Do("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		return err
	}
	_, err = db.Do("SET", cache.Prefix+key.String(), b)
	return err
}

// SetMulti sets data
func (cache *Cache) SetMulti(keys []*datastore.Key, src interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for i, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		b, err := encode(reflect.Indirect(reflect.ValueOf(src)).Index(i).Interface())
		if err != nil {
			return err
		}
		if cache.TTL > 0 {
			db.Send("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		}
		db.Send("SET", cache.Prefix+key.String(), b)
	}
	_, err := db.Do("EXEC")
	return err
}

// Del dels data
func (cache *Cache) Del(key *datastore.Key) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", cache.Prefix+key.String())
	return err
}

// DelMulti dels multi data
func (cache *Cache) DelMulti(keys []*datastore.Key) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for _, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		db.Send("DEL", cache.Prefix+key.String())
	}
	_, err := db.Do("EXEC")
	return err
}
<commit_msg>fix redis return nil when skip<commit_after>package redis

import (
	"bytes"
	"encoding/gob"
	"reflect"
	"time"

	"cloud.google.com/go/datastore"
	"github.com/acoshift/ds"
	"github.com/garyburd/redigo/redis"
)

// Cache implement Cache interface
type Cache struct {
	Pool   *redis.Pool
	Prefix string
	TTL    time.Duration
	Skip   func(*datastore.Key) bool
}

func encode(v interface{}) ([]byte, error) {
	w := &bytes.Buffer{}
	err := gob.NewEncoder(w).Encode(v)
	if err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}

func decode(b []byte, v interface{}) error {
	return gob.NewDecoder(bytes.NewReader(b)).Decode(v)
}

// Get gets data
func (cache *Cache) Get(key *datastore.Key, dst interface{}) error {
	if cache.Skip != nil && cache.Skip(key) {
		return ds.ErrCacheNotFound
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := redis.Bytes(db.Do("GET", cache.Prefix+key.String()))
	if err != nil {
		return err
	}
	if len(b) == 0 {
		return ds.ErrCacheNotFound
	}
	return decode(b, dst)
}

// GetMulti gets multi data
func (cache *Cache) GetMulti(keys []*datastore.Key, dst interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	for _, key := range keys {
		db.Send("GET", cache.Prefix+key.String())
	}
	err := db.Flush()
	if err != nil {
		return err
	}
	for i := range keys {
		b, err := redis.Bytes(db.Receive())
		if err != nil {
			return err
		}
		if len(b) > 0 {
			decode(b, reflect.Indirect(reflect.ValueOf(dst)).Index(i).Interface())
		}
	}
	return nil
}

// Set sets data
func (cache *Cache) Set(key *datastore.Key, src interface{}) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := encode(src)
	if err != nil {
		return err
	}
	if cache.TTL > 0 {
		_, err = db.Do("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		return err
	}
	_, err = db.Do("SET", cache.Prefix+key.String(), b)
	return err
}

// SetMulti sets data
func (cache *Cache) SetMulti(keys []*datastore.Key, src interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for i, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		b, err := encode(reflect.Indirect(reflect.ValueOf(src)).Index(i).Interface())
		if err != nil {
			return err
		}
		if cache.TTL > 0 {
			db.Send("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		}
		db.Send("SET", cache.Prefix+key.String(), b)
	}
	_, err := db.Do("EXEC")
	return err
}

// Del dels data
func (cache *Cache) Del(key *datastore.Key) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", cache.Prefix+key.String())
	return err
}

// DelMulti dels multi data
func (cache *Cache) DelMulti(keys []*datastore.Key) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for _, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		db.Send("DEL", cache.Prefix+key.String())
	}
	_, err := db.Do("EXEC")
	return err
}
<|endoftext|>


<commit_before>package hole

import (
	"bytes"
	"fmt"
	"github.com/satori/go.uuid"
	"testing"
)

func TestHeader(t *testing.T) {
	var data = []byte("data")
	var length = uint32(len(data))
	var header, err = MakeHeader(data)
	if err != nil {
		t.Fatal(err)
	}
	fmt.Printf("%v\n", header)
	var lengthGot = ParseHeader(header)

	if lengthGot != length {
		t.Fatalf("Header: except: %d, got: %d", length, lengthGot)
	}
}

func TestEncodeAndDecodePacket(t *testing.T) {
	sessionId := uuid.NewV4().Bytes()
	data := []byte("This is a payload.")

	payload := EncodePacket(sessionId, data)

	sid, d := DecodePacket(payload)

	if !bytes.Equal(sid, sessionId) {
		t.Fatalf("SessionId: except: %x, got: %x", sessionId, sid)
	}

	if !bytes.Equal(d, data) {
		t.Fatalf("Payload: except: %x, got: %x", data, d)
	}
}

type writer struct {
	t      *testing.T
	except []byte
}

func (w *writer) Write(buf []byte) (n int, err error) {
	if !bytes.Equal(w.except, buf) {
		w.t.Fatalf("Payload: except: %x, got: %x", w.except, buf)
	}
	return len(buf), nil
}

func (w *writer) Close() error {
	return nil
}

func TestPipeThenClose(t *testing.T) {
	r := NewReadStream()
	data := []byte("This is a payload.")

	w := new(writer)
	w.t = t
	w.except = data

	go PipeThenClose(r, w)

	r.FeedData(data)
	r.FeedEOF()
}
<commit_msg>remove info code<commit_after>package hole

import (
	"bytes"
	"github.com/satori/go.uuid"
	"testing"
)

func TestHeader(t *testing.T) {
	var data = []byte("data")
	var length = uint32(len(data))
	var header, err = MakeHeader(data)
	if err != nil {
		t.Fatal(err)
	}
	var lengthGot = ParseHeader(header)

	if lengthGot != length {
		t.Fatalf("Header: except: %d, got: %d", length, lengthGot)
	}
}

func TestEncodeAndDecodePacket(t *testing.T) {
	sessionId := uuid.NewV4().Bytes()
	data := []byte("This is a payload.")

	payload := EncodePacket(sessionId, data)

	sid, d := DecodePacket(payload)

	if !bytes.Equal(sid, sessionId) {
		t.Fatalf("SessionId: except: %x, got: %x", sessionId, sid)
	}

	if !bytes.Equal(d, data) {
		t.Fatalf("Payload: except: %x, got: %x", data, d)
	}
}

type writer struct {
	t      *testing.T
	except []byte
}

func (w *writer) Write(buf []byte) (n int, err error) {
	if !bytes.Equal(w.except, buf) {
		w.t.Fatalf("Payload: except: %x, got: %x", w.except, buf)
	}
	return len(buf), nil
}

func (w *writer) Close() error {
	return nil
}

func TestPipeThenClose(t *testing.T) {
	r := NewReadStream()
	data := []byte("This is a payload.")

	w := new(writer)
	w.t = t
	w.except = data

	go PipeThenClose(r, w)

	r.FeedData(data)
	r.FeedEOF()
}
<|endoftext|>


<commit_before>package calendar

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/patrickmn/go-cache"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/calendar/v3"
)

// Retrieve a token, saves the token, then returns the generated client.
func getClient(config *oauth2.Config) (*http.Client, error) {
	tokFile := "token.json"
	tok, err := tokenFromFile(tokFile)
	if err != nil {
		tok, err = tokenFromEnv()
		if err != nil {
			tok, err = getTokenFromWeb(config)
			if err != nil {
				return nil, fmt.Errorf("Failed to get token from web: %v", err)
			}
			if err = saveToken(tokFile, tok); err != nil {
				return nil, fmt.Errorf("Failed to save token: %v", err)
			}
		}
	}
	return config.Client(context.Background(), tok), nil
}

// Request a token from the web, then returns the retrieved token.
func getTokenFromWeb(config *oauth2.Config) (*oauth2.Token, error) {
	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
	fmt.Printf("Go to the following link in your browser then type the "+
		"authorization code: \n%v\n", authURL)

	var authCode string
	if _, err := fmt.Scan(&authCode); err != nil {
		return nil, fmt.Errorf("Unable to read authorization code: %v", err)
	}

	tok, err := config.Exchange(context.TODO(), authCode)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve token from web: %v", err)
	}
	return tok, nil
}

func tokenFromEnv() (*oauth2.Token, error) {
	tok := oauth2.Token{}
	if err := json.Unmarshal([]byte(os.Getenv("CALENDAR_TOKENS")), &tok); err != nil {
		return nil, err
	}
	return &tok, nil
}

// Retrieves a token from a local file.
func tokenFromFile(file string) (*oauth2.Token, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	tok := &oauth2.Token{}
	err = json.NewDecoder(f).Decode(tok)
	return tok, err
}

// Saves a token to a file path.
func saveToken(path string, token *oauth2.Token) error {
	fmt.Printf("Saving credential file to: %s\n", path)
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("Unable to cache oauth token: %v", err)
	}
	defer f.Close()
	return json.NewEncoder(f).Encode(token)
}

type CalendarScheduleService struct {
	cache   *cache.Cache
	service *calendar.Service
}

func NewCalendarScheduleService() (*CalendarScheduleService, error) {
	// If modifying these scopes, delete your previously saved token.json.
	config, err := google.ConfigFromJSON([]byte(os.Getenv("GOOGLE_CREDENTIALS")), calendar.CalendarReadonlyScope)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse client secret file to config: %v", err)
	}
	client, err := getClient(config)
	if err != nil {
		return nil, fmt.Errorf("Failed to get calendar client: %v", err)
	}

	srv, err := calendar.New(client)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve Calendar client: %v", err)
	}
	return &CalendarScheduleService{
		cache:   cache.New(time.Minute*10, time.Minute*20),
		service: srv,
	}, nil
}

func (srv *CalendarScheduleService) GetSchedule(calendarId string) ([]*calendar.TimePeriod, error) {
	cached, found := srv.cache.Get(calendarId)
	if found {
		return cached.([]*calendar.TimePeriod), nil
	}

	request := &calendar.FreeBusyRequest{
		Items: []*calendar.FreeBusyRequestItem{
			&calendar.FreeBusyRequestItem{
				Id: calendarId,
			},
		},
		TimeMin: time.Now().Add(time.Hour * -1).Format(time.RFC3339),
		TimeMax: time.Now().Add(time.Hour * 24 * 7).Format(time.RFC3339),
	}
	log.Printf("Fetching calendar for %s", calendarId)
	resp, err := srv.service.Freebusy.Query(request).Do()
	if err != nil {
		return nil, fmt.Errorf("Failed to request free/busy: %v", err)
	}
	srv.cache.Set(calendarId, resp.Calendars[calendarId].Busy, cache.DefaultExpiration)
	return resp.Calendars[calendarId].Busy, nil
}
<commit_msg>Always get calendar token from env<commit_after>package calendar

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/patrickmn/go-cache"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/calendar/v3"
)

// Retrieve a token, saves the token, then returns the generated client.
func getClient(config *oauth2.Config) (*http.Client, error) {
	tok, err := tokenFromEnv()
	if err != nil {
		return nil, fmt.Errorf("Failed to get calendar token from env: %v", err)
	}
	return config.Client(context.Background(), tok), nil
}

func tokenFromEnv() (*oauth2.Token, error) {
	tok := oauth2.Token{}
	if err := json.Unmarshal([]byte(os.Getenv("CALENDAR_TOKENS")), &tok); err != nil {
		return nil, err
	}
	return &tok, nil
}

type CalendarScheduleService struct {
	cache   *cache.Cache
	service *calendar.Service
}

func NewCalendarScheduleService() (*CalendarScheduleService, error) {
	// If modifying these scopes, delete your previously saved token.json.
	config, err := google.ConfigFromJSON([]byte(os.Getenv("GOOGLE_CREDENTIALS")), calendar.CalendarReadonlyScope)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse client secret file to config: %v", err)
	}
	client, err := getClient(config)
	if err != nil {
		return nil, fmt.Errorf("Failed to get calendar client: %v", err)
	}

	srv, err := calendar.New(client)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve Calendar client: %v", err)
	}
	return &CalendarScheduleService{
		cache:   cache.New(time.Minute*10, time.Minute*20),
		service: srv,
	}, nil
}

func (srv *CalendarScheduleService) GetSchedule(calendarId string) ([]*calendar.TimePeriod, error) {
	cached, found := srv.cache.Get(calendarId)
	if found {
		return cached.([]*calendar.TimePeriod), nil
	}

	request := &calendar.FreeBusyRequest{
		Items: []*calendar.FreeBusyRequestItem{
			{
				Id: calendarId,
			},
		},
		TimeMin: time.Now().Add(time.Hour * -1).Format(time.RFC3339),
		TimeMax: time.Now().Add(time.Hour * 24 * 7).Format(time.RFC3339),
	}
	log.Printf("Fetching calendar for %s", calendarId)
	resp, err := srv.service.Freebusy.Query(request).Do()
	if err != nil {
		return nil, fmt.Errorf("Failed to request free/busy: %v", err)
	}
	srv.cache.Set(calendarId, resp.Calendars[calendarId].Busy, cache.DefaultExpiration)
	return resp.Calendars[calendarId].Busy, nil
}
<|endoftext|>


<commit_before>package ilang

import "strings"

func (ic *Compiler) CollectGarbage() {
	//Erm garbage collection???
	for name, variable := range ic.Scope[len(ic.Scope)-1] {
		if strings.Contains(name, "_used") {
			var ok = false
			if ic.LastDefinedType.Detail != nil {
				_, ok = ic.LastDefinedType.Detail.Table[strings.Split(name, "_")[0]]
			}
			if variable == Unused && !(ic.GetFlag(InMethod) && ok ) {
				ic.RaiseError("unused variable! ", strings.Split(name, "_")[0])
			}
		}

		if ic.Scope[len(ic.Scope)-1][name+"."] != Protected { //Protected variables
			if ic.GetFlag(InMethod) && name == ic.LastDefinedType.Name {
				continue
			}

			//Possible memory leak, TODO check up on this.
			if _, ok := ic.DefinedTypes[name]; ic.GetFlag(InMethod) && ok {
				continue
			}

			if (variable.IsUser() != Undefined)  || (variable.SubType != nil && (variable.SubType.Push != "PUSH" || variable.SubType.SubType != nil)) {

				if !variable.Empty() {
				ic.Collect(variable)
				ic.Assembly(variable.Push, " ", name)
				ic.Assembly(ic.RunFunction("collect_m_"+variable.GetComplexName()))
				}
			}
		}
	}
}

var AlreadyGeneratedACollectionMethodFor = make(map[string]bool)

func (t Type) Free(pointer string) string {
	if (t.IsUser() == Undefined && t.SubType == nil) || (t.SubType != nil && t.SubType.Push == "PUSH" && t.SubType.SubType == nil) {
		return ""
	}
	if t.Empty() {
		return ""
	}

	return "IF "+pointer+"\nPUSH "+pointer+
	"\nHEAP\nRUN collect_m_"+t.GetComplexName()+
	"\nMUL "+pointer+" -1 "+pointer+"\nPUSH "+pointer+"\nHEAP\nEND"
}

func (t Type) FreeChildren(pointer string) string {
	if (t.IsUser() == Undefined && t.SubType == nil) || (t.SubType != nil && t.SubType.Push == "PUSH" && t.SubType.SubType == nil) {
		return ""
	}
	if t.Empty() {
		return ""
	}

	return "SHARE "+pointer+"\nRUN collect_m_"+t.GetComplexName()
}

func (ic *Compiler) Collect(t Type) {
	if AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] {
		return
	}

	if t.Empty() {
		return
	}

	if t.IsUser() == Undefined  {
		//TODO collect lists, tables and other complex types!

		for _, collection := range Collections {
			collection(ic, t)
		}
		AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] = true

		return
	}

	for _, element := range t.Detail.Elements {
		ic.Collect(element)
	}

	var scope = ic.Scope
	ic.GainScope()
	ic.Library("FUNCTION collect_m_", t.GetComplexName())
	ic.GainScope()
	ic.Library("GRAB variable")
	ic.Library("PLACE variable")

	for i, element := range t.Detail.Elements {
		if element.Push == "SHARE" {
			var tmp = ic.Tmp("gc")
			ic.Library("PUSH ", i)
			ic.Library("GET ", tmp)
			ic.Library("ADD ", tmp, " 0 ", tmp)

			ic.Library(element.Free(tmp))
		}
	}
	ic.LoseScope()
	ic.Library("RETURN")
	ic.Scope = scope

	AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] = true
}
<commit_msg>Fix garbage collection bug.<commit_after>package ilang

import "strings"

func (ic *Compiler) CollectGarbage() {
	//Erm garbage collection???
	for name, variable := range ic.Scope[len(ic.Scope)-1] {
		if strings.Contains(name, "_used") {
			var ok = false
			if ic.LastDefinedType.Detail != nil {
				_, ok = ic.LastDefinedType.Detail.Table[strings.Split(name, "_")[0]]
			}
			if variable == Unused && !(ic.GetFlag(InMethod) && ok ) {
				ic.RaiseError("unused variable! ", strings.Split(name, "_")[0])
			}
		}

		if ic.Scope[len(ic.Scope)-1][name+"."] != Protected { //Protected variables
			if ic.GetFlag(InMethod) && name == ic.LastDefinedType.Name {
				continue
			}

			//Possible memory leak, TODO check up on this.
			if _, ok := ic.DefinedTypes[name]; ic.GetFlag(InMethod) && ok {
				continue
			}

			if (variable.IsUser() != Undefined)  || (variable.SubType != nil && (variable.SubType.Push != "PUSH" || variable.SubType.SubType != nil)) {

				if !variable.Empty() {
				ic.Collect(variable)
				ic.Assembly(variable.Push, " ", name)
				ic.Assembly(ic.RunFunction("collect_m_"+variable.GetComplexName()))
				}
			}
		}
	}
}

var AlreadyGeneratedACollectionMethodFor = make(map[string]bool)

func (t Type) Free(pointer string) string {
	if (t.IsUser() == Undefined && t.SubType == nil) || (t.SubType != nil && t.SubType.Push == "PUSH" && t.SubType.SubType == nil) {

		if (t.Push == "SHARE") {
			return "IF "+pointer+"\nMUL "+pointer+" -1 "+pointer+"\nPUSH "+pointer+"\nHEAP\nEND\n"
		}

		return ""
	}
	if t.Empty() {
		return ""
	}

	return "IF "+pointer+"\nPUSH "+pointer+
	"\nHEAP\nRUN collect_m_"+t.GetComplexName()+
	"\nMUL "+pointer+" -1 "+pointer+"\nPUSH "+pointer+"\nHEAP\nEND"
}

func (t Type) FreeChildren(pointer string) string {
	if (t.IsUser() == Undefined && t.SubType == nil) || (t.SubType != nil && t.SubType.Push == "PUSH" && t.SubType.SubType == nil) {
		return ""
	}
	if t.Empty() {
		return ""
	}

	return "SHARE "+pointer+"\nRUN collect_m_"+t.GetComplexName()
}

func (ic *Compiler) Collect(t Type) {
	if AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] {
		return
	}

	if t.Empty() {
		return
	}

	if t.IsUser() == Undefined  {
		//TODO collect lists, tables and other complex types!

		for _, collection := range Collections {
			collection(ic, t)
		}
		AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] = true

		return
	}

	for _, element := range t.Detail.Elements {
		ic.Collect(element)
	}

	var scope = ic.Scope
	ic.GainScope()
	ic.Library("FUNCTION collect_m_", t.GetComplexName())
	ic.GainScope()
	ic.Library("GRAB variable")
	ic.Library("PLACE variable")

	for i, element := range t.Detail.Elements {
		if element.Push == "SHARE" {
			var tmp = ic.Tmp("gc")
			ic.Library("PUSH ", i)
			ic.Library("GET ", tmp)
			ic.Library("ADD ", tmp, " 0 ", tmp)

			ic.Library(element.Free(tmp))

			ic.Library("PUSH ", i)
			ic.Library("SET 0")
		}
	}
	ic.LoseScope()
	ic.Library("RETURN")
	ic.Scope = scope

	AlreadyGeneratedACollectionMethodFor[t.GetComplexName()] = true
}
<|endoftext|>


<commit_before>// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package spec

import (
	"bufio"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"go.chromium.org/luci/vpython/api/vpython"

	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	cproto "go.chromium.org/luci/common/proto"
	"go.chromium.org/luci/common/system/filesystem"

	"golang.org/x/net/context"
)

// Suffix is the filesystem suffix for a script's partner specification file.
//
// See LoadForScript for more information.
const Suffix = ".vpython"

// DefaultCommonSpecNames is the name of the "common" specification file.
//
// If a script doesn't explicitly specific a specification file, "vpython" will
// automatically walk up from the script's directory towards filesystem root
// and will use the first file named CommonName that it finds. This enables
// repository-wide and shared environment specifications.
var DefaultCommonSpecNames = []string{
	"common" + Suffix,
}

const (
	// DefaultInlineBeginGuard is the default loader InlineBeginGuard value.
	DefaultInlineBeginGuard = "[VPYTHON:BEGIN]"
	// DefaultInlineEndGuard is the default loader InlineEndGuard value.
	DefaultInlineEndGuard = "[VPYTHON:END]"
)

// Load loads an specification file text protobuf from the supplied path.
func Load(path string, spec *vpython.Spec) error {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return errors.Annotate(err, "failed to load file from: %s", path).Err()
	}

	return Parse(string(content), spec)
}

// Parse loads a specification message from a content string.
func Parse(content string, spec *vpython.Spec) error {
	if err := cproto.UnmarshalTextML(content, spec); err != nil {
		return errors.Annotate(err, "failed to unmarshal vpython.Spec").Err()
	}
	return nil
}

// Loader implements the generic ability to load a "vpython" spec file.
type Loader struct {
	// InlineBeginGuard is a string that signifies the beginning of an inline
	// specification. If empty, DefaultInlineBeginGuard will be used.
	InlineBeginGuard string
	// InlineEndGuard is a string that signifies the end of an inline
	// specification. If empty, DefaultInlineEndGuard will be used.
	InlineEndGuard string

	// CommonFilesystemBarriers is a list of filenames. During common spec, Loader
	// walks directories towards root looking for a file named CommonName. If a
	// directory is observed to contain a file in CommonFilesystemBarriers, the
	// walk will terminate after processing that directory.
	CommonFilesystemBarriers []string

	// CommonSpecNames, if not empty, is the list of common "vpython" spec files
	// to use. If empty, DefaultCommonSpecNames will be used.
	//
	// Names will be considered in the order that they appear.
	CommonSpecNames []string
}

// LoadForScript attempts to load a spec file for the specified script. If
// nothing went wrong, a nil error will be returned. If a spec file was
// identified, it will also be returned. Otherwise, a nil spec will be returned.
//
// Spec files can be specified in a variety of ways. This function will look for
// them in the following order, and return the first one that was identified:
//
//	- Partner File
//	- Inline
//
// Partner File
// ============
//
// LoadForScript traverses the filesystem to find the specification file that is
// naturally associated with the specified
// path.
//
// If the path is a Python script (e.g, "/path/to/test.py"), isModule will be
// false, and the file will be found at "/path/to/test.py.vpython".
//
// If the path is a Python module (isModule is true), findForScript walks
// upwards in the directory structure, looking for a file that shares a module
// directory name and ends with ".vpython". For example, for module:
//
//	/path/to/foo/bar/baz/__init__.py
//	/path/to/foo/bar/__init__.py
//	/path/to/foo/__init__.py
//	/path/to/foo.vpython
//
// LoadForScript will first look at "/path/to/foo/bar/baz", then walk upwards
// until it either hits a directory that doesn't contain an "__init__.py" file,
// or finds the ES path. In this case, for module "foo.bar.baz", it will
// identify "/path/to/foo.vpython" as the ES file for that module.
//
// Inline
// ======
//
// LoadForScript scans through the contents of the file at path and attempts to
// load specification boundaries.
//
// If the file at path does not exist, or if the file does not contain spec
// guards, a nil spec will be returned.
//
// The embedded specification is a text protobuf embedded within the file. To
// parse it, the file is scanned line-by-line for a beginning and ending guard.
// The content between those guards is minimally processed, then interpreted as
// a text protobuf.
//
//	[VPYTHON:BEGIN]
//	wheel {
//	  path: ...
//	  version: ...
//	}
//	[VPYTHON:END]
//
// To allow VPYTHON directives to be embedded in a language-compatible manner
// (with indentation, comments, etc.), the processor will identify any common
// characters preceding the BEGIN and END clauses. If they match, those
// characters will be automatically stripped out of the intermediate lines. This
// can be used to embed the directives in comments:
//
//	// [VPYTHON:BEGIN]
//	// wheel {
//	//   path: ...
//	//   version: ...
//	// }
//	// [VPYTHON:END]
//
// In this case, the "// " characters will be removed.
//
// Common
// ======
//
// LoadForScript will examine successive parent directories starting from the
// script's location, looking for a file named in CommonSpecNames. If it finds
// one, it will use that as the specification file. This enables scripts to
// implicitly share an specification.
func (l *Loader) LoadForScript(c context.Context, path string, isModule bool) (*vpython.Spec, error) {
	// Partner File: Try loading the spec from an adjacent file.
	specPath, err := l.findForScript(path, isModule)
	if err != nil {
		return nil, errors.Annotate(err, "failed to scan for filesystem spec").Err()
	}
	if specPath != "" {
		var spec vpython.Spec
		if err := Load(specPath, &spec); err != nil {
			return nil, err
		}

		logging.Infof(c, "Loaded specification from: %s", specPath)
		return &spec, nil
	}

	// Inline: Try and parse the main script for the spec file.
	mainScript := path
	if isModule {
		// Module.
		mainScript = filepath.Join(mainScript, "__main__.py")
	}
	switch spec, err := l.parseFrom(mainScript); {
	case err != nil:
		return nil, errors.Annotate(err, "failed to parse inline spec from: %s", mainScript).Err()

	case spec != nil:
		logging.Infof(c, "Loaded inline spec from: %s", mainScript)
		return spec, nil
	}

	// Common: Try and identify a common specification file.
	switch path, err := l.findCommonWalkingFrom(filepath.Dir(mainScript)); {
	case err != nil:
		return nil, err

	case path != "":
		var spec vpython.Spec
		if err := Load(path, &spec); err != nil {
			return nil, err
		}

		logging.Infof(c, "Loaded common spec from: %s", path)
		return &spec, nil
	}

	// Couldn't identify a specification file.
	return nil, nil
}

func (l *Loader) findForScript(path string, isModule bool) (string, error) {
	if !isModule {
		path += Suffix
		if st, err := os.Stat(path); err != nil || st.IsDir() {
			// File does not exist at this path.
			return "", nil
		}
		return path, nil
	}

	// If it's a directory, scan for a ".vpython" file until we don't have a
	// __init__.py.
	for {
		prev := path

		// Directory must be a Python module.
		initPath := filepath.Join(path, "__init__.py")
		if _, err := os.Stat(initPath); err != nil {
			if os.IsNotExist(err) {
				// Not a Python module, so we're done our search.
				return "", nil
			}
			return "", errors.Annotate(err, "failed to stat for: %s", path).Err()
		}

		// Does a spec file exist for this path?
		specPath := path + Suffix
		switch _, err := os.Stat(specPath); {
		case err == nil:
			// Found the file.
			return specPath, nil

		case os.IsNotExist(err):
			// Recurse to parent.
			path = filepath.Dir(path)
			if path == prev {
				// Finished recursing, no ES file.
				return "", nil
			}

		default:
			return "", errors.Annotate(err, "failed to check for spec file at: %s", specPath).Err()
		}
	}
}

func (l *Loader) parseFrom(path string) (*vpython.Spec, error) {
	fd, err := os.Open(path)
	if err != nil {
		return nil, errors.Annotate(err, "failed to open file").Err()
	}
	defer fd.Close()

	// Determine our guards.
	beginGuard := l.InlineBeginGuard
	if beginGuard == "" {
		beginGuard = DefaultInlineBeginGuard
	}

	endGuard := l.InlineEndGuard
	if endGuard == "" {
		endGuard = DefaultInlineEndGuard
	}

	s := bufio.NewScanner(fd)
	var (
		content   []string
		beginLine string
		endLine   string
		inRegion  = false
	)
	for s.Scan() {
		line := strings.TrimSpace(s.Text())
		if !inRegion {
			inRegion = strings.HasSuffix(line, beginGuard)
			beginLine = line
		} else {
			if strings.HasSuffix(line, endGuard) {
				// Finished processing.
				endLine = line
				break
			}
			content = append(content, line)
		}
	}
	if err := s.Err(); err != nil {
		return nil, errors.Annotate(err, "error scanning file").Err()
	}
	if len(content) == 0 {
		return nil, nil
	}
	if endLine == "" {
		return nil, errors.New("unterminated inline spec file")
	}

	// If we have a common begin/end prefix, trim it from each content line that
	// also has it.
	prefix := beginLine[:len(beginLine)-len(beginGuard)]
	if endLine[:len(endLine)-len(endGuard)] != prefix {
		prefix = ""
	}
	if prefix != "" {
		for i, line := range content {
			if len(line) < len(prefix) {
				// This line is shorter than the prefix. Does the part of that line that
				// exists match the prefix up until that point?
				if line == prefix[:len(line)] {
					// Yes, so empty line.
					line = ""
				}
			} else {
				line = strings.TrimPrefix(line, prefix)
			}
			content[i] = line
		}
	}

	// Process the resulting file.
	var spec vpython.Spec
	if err := Parse(strings.Join(content, "\n"), &spec); err != nil {
		return nil, errors.Annotate(err, "failed to parse spec file from: %s", path).Err()
	}
	return &spec, nil
}

func (l *Loader) findCommonWalkingFrom(startDir string) (string, error) {
	names := l.CommonSpecNames
	if len(names) == 0 {
		names = DefaultCommonSpecNames
	}

	// Walk until we hit root.
	prevDir := ""
	for prevDir != startDir {
		// If we have any barrier files, check to see if they are present in this
		// directory. Note that this preempts any common filename in this directory.
		for _, name := range l.CommonFilesystemBarriers {
			barrierName := filepath.Join(startDir, name)
			if _, err := os.Stat(barrierName); err == nil {
				// Identified a barrier file in this directory.
				return "", nil
			}
		}

		for _, name := range names {
			checkPath := filepath.Join(startDir, name)
			switch _, err := os.Stat(checkPath); {
			case err == nil:
				return checkPath, nil

			case filesystem.IsNotExist(err):
				// Not in this directory.

			default:
				// Failed to load specification from this file.
				return "", errors.Annotate(err, "failed to stat common spec file at: %s", checkPath).Err()
			}
		}

		// Walk up a directory.
		startDir, prevDir = filepath.Dir(startDir), startDir
	}

	// Couldn't find the file.
	return "", nil
}
<commit_msg>[vpython] Do not load `.vpython` directories as specs.<commit_after>// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package spec

import (
	"bufio"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"go.chromium.org/luci/vpython/api/vpython"

	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	cproto "go.chromium.org/luci/common/proto"
	"go.chromium.org/luci/common/system/filesystem"

	"golang.org/x/net/context"
)

// Suffix is the filesystem suffix for a script's partner specification file.
//
// See LoadForScript for more information.
const Suffix = ".vpython"

// DefaultCommonSpecNames is the name of the "common" specification file.
//
// If a script doesn't explicitly specific a specification file, "vpython" will
// automatically walk up from the script's directory towards filesystem root
// and will use the first file named CommonName that it finds. This enables
// repository-wide and shared environment specifications.
var DefaultCommonSpecNames = []string{
	"common" + Suffix,
}

const (
	// DefaultInlineBeginGuard is the default loader InlineBeginGuard value.
	DefaultInlineBeginGuard = "[VPYTHON:BEGIN]"
	// DefaultInlineEndGuard is the default loader InlineEndGuard value.
	DefaultInlineEndGuard = "[VPYTHON:END]"
)

// Load loads an specification file text protobuf from the supplied path.
func Load(path string, spec *vpython.Spec) error {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return errors.Annotate(err, "failed to load file from: %s", path).Err()
	}

	return Parse(string(content), spec)
}

// Parse loads a specification message from a content string.
func Parse(content string, spec *vpython.Spec) error {
	if err := cproto.UnmarshalTextML(content, spec); err != nil {
		return errors.Annotate(err, "failed to unmarshal vpython.Spec").Err()
	}
	return nil
}

// Loader implements the generic ability to load a "vpython" spec file.
type Loader struct {
	// InlineBeginGuard is a string that signifies the beginning of an inline
	// specification. If empty, DefaultInlineBeginGuard will be used.
	InlineBeginGuard string
	// InlineEndGuard is a string that signifies the end of an inline
	// specification. If empty, DefaultInlineEndGuard will be used.
	InlineEndGuard string

	// CommonFilesystemBarriers is a list of filenames. During common spec, Loader
	// walks directories towards root looking for a file named CommonName. If a
	// directory is observed to contain a file in CommonFilesystemBarriers, the
	// walk will terminate after processing that directory.
	CommonFilesystemBarriers []string

	// CommonSpecNames, if not empty, is the list of common "vpython" spec files
	// to use. If empty, DefaultCommonSpecNames will be used.
	//
	// Names will be considered in the order that they appear.
	CommonSpecNames []string
}

// LoadForScript attempts to load a spec file for the specified script. If
// nothing went wrong, a nil error will be returned. If a spec file was
// identified, it will also be returned. Otherwise, a nil spec will be returned.
//
// Spec files can be specified in a variety of ways. This function will look for
// them in the following order, and return the first one that was identified:
//
//	- Partner File
//	- Inline
//
// Partner File
// ============
//
// LoadForScript traverses the filesystem to find the specification file that is
// naturally associated with the specified
// path.
//
// If the path is a Python script (e.g, "/path/to/test.py"), isModule will be
// false, and the file will be found at "/path/to/test.py.vpython".
//
// If the path is a Python module (isModule is true), findForScript walks
// upwards in the directory structure, looking for a file that shares a module
// directory name and ends with ".vpython". For example, for module:
//
//	/path/to/foo/bar/baz/__init__.py
//	/path/to/foo/bar/__init__.py
//	/path/to/foo/__init__.py
//	/path/to/foo.vpython
//
// LoadForScript will first look at "/path/to/foo/bar/baz", then walk upwards
// until it either hits a directory that doesn't contain an "__init__.py" file,
// or finds the ES path. In this case, for module "foo.bar.baz", it will
// identify "/path/to/foo.vpython" as the ES file for that module.
//
// Inline
// ======
//
// LoadForScript scans through the contents of the file at path and attempts to
// load specification boundaries.
//
// If the file at path does not exist, or if the file does not contain spec
// guards, a nil spec will be returned.
//
// The embedded specification is a text protobuf embedded within the file. To
// parse it, the file is scanned line-by-line for a beginning and ending guard.
// The content between those guards is minimally processed, then interpreted as
// a text protobuf.
//
//	[VPYTHON:BEGIN]
//	wheel {
//	  path: ...
//	  version: ...
//	}
//	[VPYTHON:END]
//
// To allow VPYTHON directives to be embedded in a language-compatible manner
// (with indentation, comments, etc.), the processor will identify any common
// characters preceding the BEGIN and END clauses. If they match, those
// characters will be automatically stripped out of the intermediate lines. This
// can be used to embed the directives in comments:
//
//	// [VPYTHON:BEGIN]
//	// wheel {
//	//   path: ...
//	//   version: ...
//	// }
//	// [VPYTHON:END]
//
// In this case, the "// " characters will be removed.
//
// Common
// ======
//
// LoadForScript will examine successive parent directories starting from the
// script's location, looking for a file named in CommonSpecNames. If it finds
// one, it will use that as the specification file. This enables scripts to
// implicitly share an specification.
func (l *Loader) LoadForScript(c context.Context, path string, isModule bool) (*vpython.Spec, error) {
	// Partner File: Try loading the spec from an adjacent file.
	specPath, err := l.findForScript(path, isModule)
	if err != nil {
		return nil, errors.Annotate(err, "failed to scan for filesystem spec").Err()
	}
	if specPath != "" {
		var spec vpython.Spec
		if err := Load(specPath, &spec); err != nil {
			return nil, err
		}

		logging.Infof(c, "Loaded specification from: %s", specPath)
		return &spec, nil
	}

	// Inline: Try and parse the main script for the spec file.
	mainScript := path
	if isModule {
		// Module.
		mainScript = filepath.Join(mainScript, "__main__.py")
	}
	switch spec, err := l.parseFrom(mainScript); {
	case err != nil:
		return nil, errors.Annotate(err, "failed to parse inline spec from: %s", mainScript).Err()

	case spec != nil:
		logging.Infof(c, "Loaded inline spec from: %s", mainScript)
		return spec, nil
	}

	// Common: Try and identify a common specification file.
	switch path, err := l.findCommonWalkingFrom(filepath.Dir(mainScript)); {
	case err != nil:
		return nil, err

	case path != "":
		var spec vpython.Spec
		if err := Load(path, &spec); err != nil {
			return nil, err
		}

		logging.Infof(c, "Loaded common spec from: %s", path)
		return &spec, nil
	}

	// Couldn't identify a specification file.
	return nil, nil
}

func (l *Loader) findForScript(path string, isModule bool) (string, error) {
	if !isModule {
		path += Suffix
		if st, err := os.Stat(path); err != nil || st.IsDir() {
			// File does not exist at this path.
			return "", nil
		}
		return path, nil
	}

	// If it's a directory, scan for a ".vpython" file until we don't have a
	// __init__.py.
	for {
		prev := path

		// Directory must be a Python module.
		initPath := filepath.Join(path, "__init__.py")
		if _, err := os.Stat(initPath); err != nil {
			if os.IsNotExist(err) {
				// Not a Python module, so we're done our search.
				return "", nil
			}
			return "", errors.Annotate(err, "failed to stat for: %s", path).Err()
		}

		// Does a spec file exist for this path?
		specPath := path + Suffix
		switch st, err := os.Stat(specPath); {
		case err == nil && !st.IsDir():
			// Found the file.
			return specPath, nil

		case os.IsNotExist(err):
			// Recurse to parent.
			path = filepath.Dir(path)
			if path == prev {
				// Finished recursing, no ES file.
				return "", nil
			}

		default:
			return "", errors.Annotate(err, "failed to check for spec file at: %s", specPath).Err()
		}
	}
}

func (l *Loader) parseFrom(path string) (*vpython.Spec, error) {
	fd, err := os.Open(path)
	if err != nil {
		return nil, errors.Annotate(err, "failed to open file").Err()
	}
	defer fd.Close()

	// Determine our guards.
	beginGuard := l.InlineBeginGuard
	if beginGuard == "" {
		beginGuard = DefaultInlineBeginGuard
	}

	endGuard := l.InlineEndGuard
	if endGuard == "" {
		endGuard = DefaultInlineEndGuard
	}

	s := bufio.NewScanner(fd)
	var (
		content   []string
		beginLine string
		endLine   string
		inRegion  = false
	)
	for s.Scan() {
		line := strings.TrimSpace(s.Text())
		if !inRegion {
			inRegion = strings.HasSuffix(line, beginGuard)
			beginLine = line
		} else {
			if strings.HasSuffix(line, endGuard) {
				// Finished processing.
				endLine = line
				break
			}
			content = append(content, line)
		}
	}
	if err := s.Err(); err != nil {
		return nil, errors.Annotate(err, "error scanning file").Err()
	}
	if len(content) == 0 {
		return nil, nil
	}
	if endLine == "" {
		return nil, errors.New("unterminated inline spec file")
	}

	// If we have a common begin/end prefix, trim it from each content line that
	// also has it.
	prefix := beginLine[:len(beginLine)-len(beginGuard)]
	if endLine[:len(endLine)-len(endGuard)] != prefix {
		prefix = ""
	}
	if prefix != "" {
		for i, line := range content {
			if len(line) < len(prefix) {
				// This line is shorter than the prefix. Does the part of that line that
				// exists match the prefix up until that point?
				if line == prefix[:len(line)] {
					// Yes, so empty line.
					line = ""
				}
			} else {
				line = strings.TrimPrefix(line, prefix)
			}
			content[i] = line
		}
	}

	// Process the resulting file.
	var spec vpython.Spec
	if err := Parse(strings.Join(content, "\n"), &spec); err != nil {
		return nil, errors.Annotate(err, "failed to parse spec file from: %s", path).Err()
	}
	return &spec, nil
}

func (l *Loader) findCommonWalkingFrom(startDir string) (string, error) {
	names := l.CommonSpecNames
	if len(names) == 0 {
		names = DefaultCommonSpecNames
	}

	// Walk until we hit root.
	prevDir := ""
	for prevDir != startDir {
		// If we have any barrier files, check to see if they are present in this
		// directory. Note that this preempts any common filename in this directory.
		for _, name := range l.CommonFilesystemBarriers {
			barrierName := filepath.Join(startDir, name)
			if _, err := os.Stat(barrierName); err == nil {
				// Identified a barrier file in this directory.
				return "", nil
			}
		}

		for _, name := range names {
			checkPath := filepath.Join(startDir, name)
			switch st, err := os.Stat(checkPath); {
			case err == nil && !st.IsDir():
				return checkPath, nil

			case filesystem.IsNotExist(err):
				// Not in this directory.

			default:
				// Failed to load specification from this file.
				return "", errors.Annotate(err, "failed to stat common spec file at: %s", checkPath).Err()
			}
		}

		// Walk up a directory.
		startDir, prevDir = filepath.Dir(startDir), startDir
	}

	// Couldn't find the file.
	return "", nil
}
<|endoftext|>


<commit_before>// Copyright 2016-2021 The Libsacloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package libsacloud

// Version バージョン
const Version = "2.21.1"
<commit_msg>Bump to v2.22.0<commit_after>// Copyright 2016-2021 The Libsacloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package libsacloud

// Version バージョン
const Version = "2.22.0"
<|endoftext|>


<commit_before>package goanna

import (
	"github.com/99designs/goodies/sprockets"
	"html/template"
)

type Views struct {
	*template.Template
	ViewHelper *sprockets.ViewHelper
}

func NewView(viewHelper *sprockets.ViewHelper) Views {
	v := Views{nil, viewHelper}
	v.Init()
	return v
}

func (v *Views) Init() {
	if v.Template == nil {
		v.Template = template.New("Template")
	}

	v.Template.Funcs(template.FuncMap{
		"urlFor":     UrlFor,
		"stylesheet": v.ViewHelper.StylesheetLinkTag,
		"javascript": v.ViewHelper.JavascriptTag,
	})
}
<commit_msg>Simplify view<commit_after>package goanna

import (
	"github.com/99designs/goodies/sprockets"
	"html/template"
)

type Views struct {
	*template.Template
	AssetPipeline *sprockets.ViewHelper
}

func NewView(viewHelper *sprockets.ViewHelper) Views {
	v := Views{nil, viewHelper}
	if v.Template == nil {
		v.Template = template.New("Template")
	}

	v.Template.Funcs(template.FuncMap{
		"urlFor":     UrlFor,
		"stylesheet": v.AssetPipeline.StylesheetLinkTag,
		"javascript": v.AssetPipeline.JavascriptTag,
		"assetUrl":   v.AssetPipeline.GetAssetUrl,
	})

	return v
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"appengine"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"sync"
	"time"

	"appengine/blobstore"
	"appengine/datastore"
	"appengine/taskqueue"
	"appengine/urlfetch"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
)

func ImportOpmlTask(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	userid := r.FormValue("user")
	bk := r.FormValue("key")
	fr := blobstore.NewReader(c, appengine.BlobKey(bk))
	data, err := ioutil.ReadAll(fr)
	if err != nil {
		return
	}

	var skip int
	if s, err := strconv.Atoi(r.FormValue("skip")); err == nil {
		skip = s
	}
	c.Debugf("reader import for %v, skip %v", userid, skip)

	var userOpml []*OpmlOutline
	remaining := skip

	var proc func(label string, outlines []*OpmlOutline)
	proc = func(label string, outlines []*OpmlOutline) {
		for _, o := range outlines {
			if o.XmlUrl != "" {
				if remaining > 0 {
					remaining--
				} else if len(userOpml) < IMPORT_LIMIT {
					userOpml = append(userOpml, &OpmlOutline{
						Title:   label,
						Outline: []*OpmlOutline{o},
					})
				}
			}

			if o.Title != "" && len(o.Outline) > 0 {
				proc(o.Title, o.Outline)
			}
		}
	}

	opml := Opml{}
	if err := xml.Unmarshal(data, &opml); err != nil {
		c.Errorf("opml error: %v", err.Error())
		return
	}
	proc("", opml.Outline)

	// todo: refactor below with similar from ImportReaderTask
	wg := sync.WaitGroup{}
	wg.Add(len(userOpml))
	for i := range userOpml {
		go func(i int) {
			o := userOpml[i].Outline[0]
			if err := addFeed(c, userid, userOpml[i]); err != nil {
				c.Warningf("opml import error: %v", err.Error())
				// todo: do something here?
			}
			c.Debugf("opml import: %s, %s", o.Title, o.XmlUrl)
			wg.Done()
		}(i)
	}
	wg.Wait()

	ud := UserData{Id: "data", Parent: gn.Key(&User{Id: userid})}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		gn.Get(&ud)
		mergeUserOpml(&ud, opml.Outline...)
		_, err := gn.Put(&ud)
		return err
	}, nil); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		c.Errorf("ude update error: %v", err.Error())
		return
	}

	if len(userOpml) == IMPORT_LIMIT {
		task := taskqueue.NewPOSTTask(routeUrl("import-opml-task"), url.Values{
			"key":  {bk},
			"user": {userid},
			"skip": {strconv.Itoa(skip + IMPORT_LIMIT)},
		})
		taskqueue.Add(c, task, "import-reader")
	}
}

const IMPORT_LIMIT = 20

func ImportReaderTask(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	userid := r.FormValue("user")
	bk := r.FormValue("key")
	fr := blobstore.NewReader(c, appengine.BlobKey(bk))
	data, err := ioutil.ReadAll(fr)
	if err != nil {
		return
	}

	var skip int
	if s, err := strconv.Atoi(r.FormValue("skip")); err == nil {
		skip = s
	}

	v := struct {
		Subscriptions []struct {
			Id         string `json:"id"`
			Title      string `json:"title"`
			HtmlUrl    string `json:"htmlUrl"`
			Categories []struct {
				Id    string `json:"id"`
				Label string `json:"label"`
			} `json:"categories"`
		} `json:"subscriptions"`
	}{}
	json.Unmarshal(data, &v)
	c.Debugf("reader import for %v, skip %v, len %v", userid, skip, len(v.Subscriptions))

	end := skip + IMPORT_LIMIT
	if end > len(v.Subscriptions) {
		end = len(v.Subscriptions)
	}

	wg := sync.WaitGroup{}
	wg.Add(end - skip)
	userOpml := make([]*OpmlOutline, end-skip)

	for i := range v.Subscriptions[skip:end] {
		go func(i int) {
			sub := v.Subscriptions[skip+i]
			var label string
			if len(sub.Categories) > 0 {
				label = sub.Categories[0].Label
			}
			outline := &OpmlOutline{
				Title: label,
				Outline: []*OpmlOutline{
					&OpmlOutline{
						XmlUrl: sub.Id[5:],
						Title:  sub.Title,
					},
				},
			}
			userOpml[i] = outline
			if err := addFeed(c, userid, outline); err != nil {
				c.Warningf("reader import error: %v", err.Error())
				// todo: do something here?
			}
			c.Debugf("reader import: %s, %s", sub.Title, sub.Id)
			wg.Done()
		}(i)
	}
	wg.Wait()

	ud := UserData{Id: "data", Parent: gn.Key(&User{Id: userid})}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		gn.Get(&ud)
		mergeUserOpml(&ud, userOpml...)
		_, err := gn.Put(&ud)
		return err
	}, nil); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		c.Errorf("ude update error: %v", err.Error())
		return
	}

	if end < len(v.Subscriptions) {
		task := taskqueue.NewPOSTTask(routeUrl("import-reader-task"), url.Values{
			"key":  {bk},
			"user": {userid},
			"skip": {strconv.Itoa(skip + IMPORT_LIMIT)},
		})
		taskqueue.Add(c, task, "import-reader")
	} else {
		blobstore.Delete(c, appengine.BlobKey(bk))
	}
}

func UpdateFeeds(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Key(&Feed{}).Kind()).KeysOnly()
	q = q.Filter("n <=", time.Now())
	keys, _ := gn.GetAll(q, nil)
	for _, k := range keys {
		t := taskqueue.NewPOSTTask(routeUrl("update-feed"), url.Values{
			"feed": {k.StringID()},
		})
		if _, err := taskqueue.Add(c, t, "update-feed"); err != nil {
			c.Errorf("taskqueue error: %v", err.Error())
		}
	}
	c.Infof("updating %d feeds", len(keys))
}

func fetchFeed(c mpg.Context, origUrl, fetchUrl string) (*Feed, []*Story) {
	u, err := url.Parse(fetchUrl)
	if err == nil && u.Scheme == "" {
		u.Scheme = "http"
		origUrl = u.String()
		fetchUrl = origUrl
	}

	cl := &http.Client{
		Transport: &urlfetch.Transport{
			Context:  c,
			Deadline: 60,
		},
	}
	if resp, err := cl.Get(fetchUrl); err == nil && resp.StatusCode == http.StatusOK {
		defer resp.Body.Close()
		b, _ := ioutil.ReadAll(resp.Body)
		if autoUrl, err := Autodiscover(b); err == nil && origUrl == fetchUrl {
			if autoU, err := url.Parse(autoUrl); err == nil {
				if autoU.Scheme == "" {
					autoU.Scheme = u.Scheme
				}
				if autoU.Host == "" {
					autoU.Host = u.Host
				}
				autoUrl = autoU.String()
			}
			return fetchFeed(c, origUrl, autoUrl)
		}
		return ParseFeed(c, origUrl, b)
	} else if err != nil {
		c.Warningf("fetch feed error: %s", err.Error())
	} else {
		c.Warningf("fetch feed error: status code: %s", resp.Status)
	}
	return nil, nil
}

func updateFeed(c mpg.Context, url string, feed *Feed, stories []*Story) error {
	gn := goon.FromContext(c)
	f := Feed{Url: url}
	if err := gn.Get(&f); err != nil {
		return errors.New(fmt.Sprintf("feed not found: %s", url))
	}

	// Compare the feed's listed update to the story's update.
	// Note: these may not be accurate, hence, only compare them to each other,
	// since they should have the same relative error.
	storyDate := f.Updated

	hasUpdated := !feed.Updated.IsZero()
	isFeedUpdated := f.Updated == feed.Updated
	if !hasUpdated {
		feed.Updated = f.Updated
	}
	feed.Date = f.Date
	f = *feed

	if hasUpdated && isFeedUpdated {
		c.Infof("feed %s already updated to %v, putting", url, feed.Updated)
		f.Updated = time.Now()
		gn.Put(&f)
		return nil
	}

	c.Debugf("hasUpdate: %v, isFeedUpdated: %v, storyDate: %v", hasUpdated, isFeedUpdated, storyDate)

	var newStories []*Story
	for _, s := range stories {
		if s.Updated.IsZero() || !s.Updated.Before(storyDate) {
			newStories = append(newStories, s)
		}
	}
	c.Debugf("%v possible stories to update", len(newStories))

	puts := []interface{}{&f}

	// find non existant stories
	fk := gn.Key(&f)
	getStories := make([]*Story, len(newStories))
	for i, s := range newStories {
		getStories[i] = &Story{Id: s.Id, Parent: fk}
	}
	err := gn.GetMulti(getStories)
	var updateStories []*Story
	for i, s := range getStories {
		if goon.NotFound(err, i) {
			updateStories = append(updateStories, newStories[i])
		} else if !newStories[i].Updated.IsZero() && !newStories[i].Updated.Equal(s.Updated) {
			newStories[i].Created = s.Created
			newStories[i].Published = s.Published
			updateStories = append(updateStories, newStories[i])
		}
	}
	c.Debugf("%v update stories", len(updateStories))

	for _, s := range updateStories {
		puts = append(puts, s)
		gn.Put(&StoryContent{
			Id:      1,
			Parent:  gn.Key(s),
			Content: s.content,
		})
	}

	c.Debugf("putting %v entities", len(puts))
	if len(puts) > 1 {
		f.Date = time.Now()
		if !hasUpdated {
			f.Updated = f.Date
		}
	}
	gn.PutMulti(puts)

	return nil
}

func UpdateFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	url := r.FormValue("feed")
	c.Debugf("update feed %s", url)
	f := Feed{Url: url}
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		return
	} else if time.Now().Before(f.NextUpdate) {
		c.Infof("feed %v already updated", url)
		return
	}
	if feed, stories := fetchFeed(c, url, url); feed != nil {
		updateFeed(c, url, feed, stories)
	} else {
		f.Errors++
		v := f.Errors + 1
		const max = 24 * 7
		if v > max {
			v = max
		}
		f.NextUpdate = time.Now().Add(time.Hour * time.Duration(v))
		gn.Put(&f)
		c.Warningf("error with %v (%v), bump next update to %v", url, f.Errors, f.NextUpdate)
	}
}
<commit_msg>Still nope<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"appengine"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"sync"
	"time"

	"appengine/blobstore"
	"appengine/datastore"
	"appengine/taskqueue"
	"appengine/urlfetch"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
)

func ImportOpmlTask(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	userid := r.FormValue("user")
	bk := r.FormValue("key")
	fr := blobstore.NewReader(c, appengine.BlobKey(bk))
	data, err := ioutil.ReadAll(fr)
	if err != nil {
		return
	}

	var skip int
	if s, err := strconv.Atoi(r.FormValue("skip")); err == nil {
		skip = s
	}
	c.Debugf("reader import for %v, skip %v", userid, skip)

	var userOpml []*OpmlOutline
	remaining := skip

	var proc func(label string, outlines []*OpmlOutline)
	proc = func(label string, outlines []*OpmlOutline) {
		for _, o := range outlines {
			if o.XmlUrl != "" {
				if remaining > 0 {
					remaining--
				} else if len(userOpml) < IMPORT_LIMIT {
					userOpml = append(userOpml, &OpmlOutline{
						Title:   label,
						Outline: []*OpmlOutline{o},
					})
				}
			}

			if o.Title != "" && len(o.Outline) > 0 {
				proc(o.Title, o.Outline)
			}
		}
	}

	opml := Opml{}
	if err := xml.Unmarshal(data, &opml); err != nil {
		c.Errorf("opml error: %v", err.Error())
		return
	}
	proc("", opml.Outline)

	// todo: refactor below with similar from ImportReaderTask
	wg := sync.WaitGroup{}
	wg.Add(len(userOpml))
	for i := range userOpml {
		go func(i int) {
			o := userOpml[i].Outline[0]
			if err := addFeed(c, userid, userOpml[i]); err != nil {
				c.Warningf("opml import error: %v", err.Error())
				// todo: do something here?
			}
			c.Debugf("opml import: %s, %s", o.Title, o.XmlUrl)
			wg.Done()
		}(i)
	}
	wg.Wait()

	ud := UserData{Id: "data", Parent: gn.Key(&User{Id: userid})}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		gn.Get(&ud)
		mergeUserOpml(&ud, opml.Outline...)
		_, err := gn.Put(&ud)
		return err
	}, nil); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		c.Errorf("ude update error: %v", err.Error())
		return
	}

	if len(userOpml) == IMPORT_LIMIT {
		task := taskqueue.NewPOSTTask(routeUrl("import-opml-task"), url.Values{
			"key":  {bk},
			"user": {userid},
			"skip": {strconv.Itoa(skip + IMPORT_LIMIT)},
		})
		taskqueue.Add(c, task, "import-reader")
	}
}

const IMPORT_LIMIT = 20

func ImportReaderTask(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	userid := r.FormValue("user")
	bk := r.FormValue("key")
	fr := blobstore.NewReader(c, appengine.BlobKey(bk))
	data, err := ioutil.ReadAll(fr)
	if err != nil {
		return
	}

	var skip int
	if s, err := strconv.Atoi(r.FormValue("skip")); err == nil {
		skip = s
	}

	v := struct {
		Subscriptions []struct {
			Id         string `json:"id"`
			Title      string `json:"title"`
			HtmlUrl    string `json:"htmlUrl"`
			Categories []struct {
				Id    string `json:"id"`
				Label string `json:"label"`
			} `json:"categories"`
		} `json:"subscriptions"`
	}{}
	json.Unmarshal(data, &v)
	c.Debugf("reader import for %v, skip %v, len %v", userid, skip, len(v.Subscriptions))

	end := skip + IMPORT_LIMIT
	if end > len(v.Subscriptions) {
		end = len(v.Subscriptions)
	}

	wg := sync.WaitGroup{}
	wg.Add(end - skip)
	userOpml := make([]*OpmlOutline, end-skip)

	for i := range v.Subscriptions[skip:end] {
		go func(i int) {
			sub := v.Subscriptions[skip+i]
			var label string
			if len(sub.Categories) > 0 {
				label = sub.Categories[0].Label
			}
			outline := &OpmlOutline{
				Title: label,
				Outline: []*OpmlOutline{
					&OpmlOutline{
						XmlUrl: sub.Id[5:],
						Title:  sub.Title,
					},
				},
			}
			userOpml[i] = outline
			if err := addFeed(c, userid, outline); err != nil {
				c.Warningf("reader import error: %v", err.Error())
				// todo: do something here?
			}
			c.Debugf("reader import: %s, %s", sub.Title, sub.Id)
			wg.Done()
		}(i)
	}
	wg.Wait()

	ud := UserData{Id: "data", Parent: gn.Key(&User{Id: userid})}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		gn.Get(&ud)
		mergeUserOpml(&ud, userOpml...)
		_, err := gn.Put(&ud)
		return err
	}, nil); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		c.Errorf("ude update error: %v", err.Error())
		return
	}

	if end < len(v.Subscriptions) {
		task := taskqueue.NewPOSTTask(routeUrl("import-reader-task"), url.Values{
			"key":  {bk},
			"user": {userid},
			"skip": {strconv.Itoa(skip + IMPORT_LIMIT)},
		})
		taskqueue.Add(c, task, "import-reader")
	} else {
		blobstore.Delete(c, appengine.BlobKey(bk))
	}
}

func UpdateFeeds(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Key(&Feed{}).Kind()).KeysOnly()
	q = q.Filter("n <=", time.Now())
	keys, _ := gn.GetAll(q, nil)
	for _, k := range keys {
		t := taskqueue.NewPOSTTask(routeUrl("update-feed"), url.Values{
			"feed": {k.StringID()},
		})
		if _, err := taskqueue.Add(c, t, "update-feed"); err != nil {
			c.Errorf("taskqueue error: %v", err.Error())
		}
	}
	c.Infof("updating %d feeds", len(keys))
}

func fetchFeed(c mpg.Context, origUrl, fetchUrl string) (*Feed, []*Story) {
	u, err := url.Parse(fetchUrl)
	if err == nil && u.Scheme == "" {
		u.Scheme = "http"
		origUrl = u.String()
		fetchUrl = origUrl
	}

	cl := urlfetch.Client(c)
	if resp, err := cl.Get(fetchUrl); err == nil && resp.StatusCode == http.StatusOK {
		defer resp.Body.Close()
		b, _ := ioutil.ReadAll(resp.Body)
		if autoUrl, err := Autodiscover(b); err == nil && origUrl == fetchUrl {
			if autoU, err := url.Parse(autoUrl); err == nil {
				if autoU.Scheme == "" {
					autoU.Scheme = u.Scheme
				}
				if autoU.Host == "" {
					autoU.Host = u.Host
				}
				autoUrl = autoU.String()
			}
			return fetchFeed(c, origUrl, autoUrl)
		}
		return ParseFeed(c, origUrl, b)
	} else if err != nil {
		c.Warningf("fetch feed error: %s", err.Error())
	} else {
		c.Warningf("fetch feed error: status code: %s", resp.Status)
	}
	return nil, nil
}

func updateFeed(c mpg.Context, url string, feed *Feed, stories []*Story) error {
	gn := goon.FromContext(c)
	f := Feed{Url: url}
	if err := gn.Get(&f); err != nil {
		return errors.New(fmt.Sprintf("feed not found: %s", url))
	}

	// Compare the feed's listed update to the story's update.
	// Note: these may not be accurate, hence, only compare them to each other,
	// since they should have the same relative error.
	storyDate := f.Updated

	hasUpdated := !feed.Updated.IsZero()
	isFeedUpdated := f.Updated == feed.Updated
	if !hasUpdated {
		feed.Updated = f.Updated
	}
	feed.Date = f.Date
	f = *feed

	if hasUpdated && isFeedUpdated {
		c.Infof("feed %s already updated to %v, putting", url, feed.Updated)
		f.Updated = time.Now()
		gn.Put(&f)
		return nil
	}

	c.Debugf("hasUpdate: %v, isFeedUpdated: %v, storyDate: %v", hasUpdated, isFeedUpdated, storyDate)

	var newStories []*Story
	for _, s := range stories {
		if s.Updated.IsZero() || !s.Updated.Before(storyDate) {
			newStories = append(newStories, s)
		}
	}
	c.Debugf("%v possible stories to update", len(newStories))

	puts := []interface{}{&f}

	// find non existant stories
	fk := gn.Key(&f)
	getStories := make([]*Story, len(newStories))
	for i, s := range newStories {
		getStories[i] = &Story{Id: s.Id, Parent: fk}
	}
	err := gn.GetMulti(getStories)
	var updateStories []*Story
	for i, s := range getStories {
		if goon.NotFound(err, i) {
			updateStories = append(updateStories, newStories[i])
		} else if !newStories[i].Updated.IsZero() && !newStories[i].Updated.Equal(s.Updated) {
			newStories[i].Created = s.Created
			newStories[i].Published = s.Published
			updateStories = append(updateStories, newStories[i])
		}
	}
	c.Debugf("%v update stories", len(updateStories))

	for _, s := range updateStories {
		puts = append(puts, s)
		gn.Put(&StoryContent{
			Id:      1,
			Parent:  gn.Key(s),
			Content: s.content,
		})
	}

	c.Debugf("putting %v entities", len(puts))
	if len(puts) > 1 {
		f.Date = time.Now()
		if !hasUpdated {
			f.Updated = f.Date
		}
	}
	gn.PutMulti(puts)

	return nil
}

func UpdateFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	url := r.FormValue("feed")
	c.Debugf("update feed %s", url)
	f := Feed{Url: url}
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		return
	} else if time.Now().Before(f.NextUpdate) {
		c.Infof("feed %v already updated", url)
		return
	}
	if feed, stories := fetchFeed(c, url, url); feed != nil {
		updateFeed(c, url, feed, stories)
	} else {
		f.Errors++
		v := f.Errors + 1
		const max = 24 * 7
		if v > max {
			v = max
		}
		f.NextUpdate = time.Now().Add(time.Hour * time.Duration(v))
		gn.Put(&f)
		c.Warningf("error with %v (%v), bump next update to %v", url, f.Errors, f.NextUpdate)
	}
}
<|endoftext|>


<commit_before>//Go beanstalkd client library
//Copyright(2012) Iwan Budi Kusnanto. See LICENSE for detail
package gobeanstalk

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"net"
	"strings"
)

//beanstalkd error
var (
	errOutOfMemory    = errors.New("Out of Memory")
	errInternalError  = errors.New("Internal Error")
	errBadFormat      = errors.New("Bad Format")
	errUnknownCommand = errors.New("Unknown Command")
	errBuried         = errors.New("Buried")
	errExpectedCrlf   = errors.New("Expected CRLF")
	errJobTooBig      = errors.New("Job Too Big")
	errDraining       = errors.New("Draining")
	errDeadlineSoon   = errors.New("Deadline Soon")
	errTimedOut       = errors.New("Timed Out")
	errNotFound       = errors.New("Not Found")
)

//gobeanstalk error
var (
	errInvalidLen = errors.New("Invalid Length")
	errUnknown    = errors.New("Unknown Error")
)

//Connection to beanstalkd
type Conn struct {
	conn   net.Conn
	addr   string
	reader *bufio.Reader
}

//create new connection
func NewConn(conn net.Conn, addr string) (*Conn, error) {
	c := new(Conn)
	c.conn = conn
	c.addr = addr
	c.reader = bufio.NewReader(conn)

	return c, nil
}

//A beanstalkd job
type Job struct {
	Id   uint64
	Body []byte
}

//Create new job
func NewJob(id uint64, body []byte) *Job {
	j := &Job{id, body}
	return j
}

//Connect to beanstalkd server
func Dial(addr string) (*Conn, error) {
	kon, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	c, err := NewConn(kon, addr)

	if err != nil {
		return nil, err
	}

	return c, nil
}

//Watching tube
func (c *Conn) Watch(tubename string) (int, error) {
	cmd := fmt.Sprintf("watch %s\r\n", tubename)

	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return -1, err
	}

	var tubeCount int
	_, err = fmt.Sscanf(resp, "WATCHING %d\r\n", &tubeCount)
	if err != nil {
		return -1, parseCommonError(resp)
	}
	return tubeCount, nil
}

/*
Ignore tube.

The "ignore" command is for consumers. It removes the named tube from the
watch list for the current connection
*/
func (c *Conn) Ignore(tubename string) (int, error) {
	//send command and read response string
	cmd := fmt.Sprintf("ignore %s\r\n", tubename)
	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return -1, err
	}

	//parse response
	var tubeCount int
	_, err = fmt.Sscanf(resp, "WATCHING %d\r\n", &tubeCount)
	if err != nil {
		if resp == "NOT_IGNORED\r\n" {
			return -1, errors.New("Not Ignored")
		}
		return -1, parseCommonError(resp)
	}
	return tubeCount, nil
}

//Reserve Job
func (c *Conn) Reserve() (*Job, error) {
	//send command and read response
	resp, err := sendGetResp(c, "reserve\r\n")
	if err != nil {
		return nil, err
	}

	//parse response
	var id uint64
	var bodyLen int

	switch {
	case strings.Index(resp, "RESERVED") == 0:
		_, err = fmt.Sscanf(resp, "RESERVED %d %d\r\n", &id, &bodyLen)
		if err != nil {
			return nil, err
		}
	case resp == "DEADLINE_SOON\r\n":
		return nil, errDeadlineSoon
	case resp == "TIMED_OUT\r\n":
		return nil, errTimedOut
	default:
		return nil, parseCommonError(resp)
	}

	//read job body
	body, err := c.readBytes()
	if err != nil {
		log.Println("failed reading body:", err.Error())
		return nil, err
	}

	body = body[:len(body)-2]
	if len(body) != bodyLen {
		return nil, errors.New(fmt.Sprintf("invalid body len = %d/%d", len(body), bodyLen))
	}

	return &Job{id, body}, nil
}

//Delete a job
func (c *Conn) Delete(id uint64) error {
	cmd := fmt.Sprintf("delete %d\r\n", id)
	expected := "DELETED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Use tube

The "use" command is for producers. Subsequent put commands will put jobs into
the tube specified by this command. If no use command has been issued, jobs
will be put into the tube named "default".
*/
func (c *Conn) Use(tubename string) error {
	//check parameter
	if len(tubename) > 200 {
		return errInvalidLen
	}

	cmd := fmt.Sprintf("use %s\r\n", tubename)
	expected := fmt.Sprintf("USING %s\r\n", tubename)
	return sendExpectExact(c, cmd, expected)
}

//Put job
func (c *Conn) Put(data []byte, pri, delay, ttr int) (uint64, error) {
	cmd := fmt.Sprintf("put %d %d %d %d\r\n", pri, delay, ttr, len(data))
	cmd = cmd + string(data) + "\r\n"

	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return 0, err
	}

	//parse Put response
	switch {
	case strings.Index(resp, "INSERTED") == 0:
		var id uint64
		_, parseErr := fmt.Sscanf(resp, "INSERTED %d\r\n", &id)
		return id, parseErr
	case strings.Index(resp, "BURIED") == 0:
		var id uint64
		fmt.Sscanf(resp, "BURIED %d\r\n", &id)
		return id, errBuried
	case resp == "EXPECTED_CRLF\r\n":
		return 0, errExpectedCrlf
	case resp == "JOB_TOO_BIG\r\n":
		return 0, errJobTooBig
	case resp == "DRAINING\r\n":
		return 0, errDraining
	default:
		return 0, parseCommonError(resp)
	}
	return 0, errUnknown
}

/*
Release a job.

The release command puts a reserved job back into the ready queue (and marks
its state as "ready") to be run by any client. It is normally used when the job
fails because of a transitory error.
	id is the job id to release.
	pri is a new priority to assign to the job.
	delay is an integer number of seconds to wait before putting the job in
		the ready queue. The job will be in the "delayed" state during this time.
*/
func (c *Conn) Release(id uint64, pri, delay int) error {
	cmd := fmt.Sprintf("release %d %d %d\r\n", id, pri, delay)
	expected := "RELEASED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Bury a job.

The bury command puts a job into the "buried" state. Buried jobs are put into a
FIFO linked list and will not be touched by the server again until a client
kicks them with the "kick" command.
	id is the job id to release.
	pri is a new priority to assign to the job.
*/
func (c *Conn) Bury(id uint64, pri int) error {
	cmd := fmt.Sprintf("bury %d %d\r\n", id, pri)
	expected := "BURIED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Touch a job

The "touch" command allows a worker to request more time to work on a job.
This is useful for jobs that potentially take a long time, but you still want
the benefits of a TTR pulling a job away from an unresponsive worker. A worker
may periodically tell the server that it's still alive and processing a job
(e.g. it may do this on DEADLINE_SOON)
*/
func (c *Conn) Touch(id uint64) error {
	cmd := fmt.Sprintf("touch %d\r\n", id)
	expected := "TOUCHED\r\n"
	return sendExpectExact(c, cmd, expected)
}

//send command and expect some exact response
func sendExpectExact(c *Conn, cmd, expected string) error {
	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return err
	}

	if resp != expected {
		return parseCommonError(resp)
	}
	return nil
}

//Send command and read response
func sendGetResp(c *Conn, cmd string) (string, error) {
	_, err := c.conn.Write([]byte(cmd))
	if err != nil {
		return "", err
	}

	//wait for response
	resp, err := c.reader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return resp, nil
}

//read bytes until \n
func (c *Conn) readBytes() ([]byte, error) {
	rsp, err := c.reader.ReadBytes('\n')
	return rsp, err
}

//parse for Common Error
func parseCommonError(str string) error {
	switch str {
	case "BURIED\r\n":
		return errBuried
	case "NOT_FOUND\r\n":
		return errNotFound
	case "OUT_OF_MEMORY\r\n":
		return errOutOfMemory
	case "INTERNAL_ERROR\r\n":
		return errInternalError
	case "BAD_FORMAT\r\n":
		return errBadFormat
	case "UNKNOWN_COMMAND\r\n":
		return errUnknownCommand
	}
	return errUnknown
}

//concat two slices of []byte
func concatSlice(slc1, slc2 []byte) []byte {
	newSlc := make([]byte, len(slc1)+len(slc2))
	copy(newSlc, slc1)
	copy(newSlc[len(slc1):], slc2)
	return newSlc
}
<commit_msg>use io.ReadFull to safely (and easily) read job body<commit_after>//Go beanstalkd client library
//Copyright(2012) Iwan Budi Kusnanto. See LICENSE for detail
package gobeanstalk

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
)

//beanstalkd error
var (
	errOutOfMemory    = errors.New("Out of Memory")
	errInternalError  = errors.New("Internal Error")
	errBadFormat      = errors.New("Bad Format")
	errUnknownCommand = errors.New("Unknown Command")
	errBuried         = errors.New("Buried")
	errExpectedCrlf   = errors.New("Expected CRLF")
	errJobTooBig      = errors.New("Job Too Big")
	errDraining       = errors.New("Draining")
	errDeadlineSoon   = errors.New("Deadline Soon")
	errTimedOut       = errors.New("Timed Out")
	errNotFound       = errors.New("Not Found")
)

//gobeanstalk error
var (
	errInvalidLen = errors.New("Invalid Length")
	errUnknown    = errors.New("Unknown Error")
)

//Connection to beanstalkd
type Conn struct {
	conn   net.Conn
	addr   string
	reader *bufio.Reader
}

//create new connection
func NewConn(conn net.Conn, addr string) (*Conn, error) {
	c := new(Conn)
	c.conn = conn
	c.addr = addr
	c.reader = bufio.NewReader(conn)

	return c, nil
}

//A beanstalkd job
type Job struct {
	Id   uint64
	Body []byte
}

//Create new job
func NewJob(id uint64, body []byte) *Job {
	j := &Job{id, body}
	return j
}

//Connect to beanstalkd server
func Dial(addr string) (*Conn, error) {
	kon, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	c, err := NewConn(kon, addr)

	if err != nil {
		return nil, err
	}

	return c, nil
}

//Watching tube
func (c *Conn) Watch(tubename string) (int, error) {
	cmd := fmt.Sprintf("watch %s\r\n", tubename)

	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return -1, err
	}

	var tubeCount int
	_, err = fmt.Sscanf(resp, "WATCHING %d\r\n", &tubeCount)
	if err != nil {
		return -1, parseCommonError(resp)
	}
	return tubeCount, nil
}

/*
Ignore tube.

The "ignore" command is for consumers. It removes the named tube from the
watch list for the current connection
*/
func (c *Conn) Ignore(tubename string) (int, error) {
	//send command and read response string
	cmd := fmt.Sprintf("ignore %s\r\n", tubename)
	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return -1, err
	}

	//parse response
	var tubeCount int
	_, err = fmt.Sscanf(resp, "WATCHING %d\r\n", &tubeCount)
	if err != nil {
		if resp == "NOT_IGNORED\r\n" {
			return -1, errors.New("Not Ignored")
		}
		return -1, parseCommonError(resp)
	}
	return tubeCount, nil
}

//Reserve Job
func (c *Conn) Reserve() (*Job, error) {
	//send command and read response
	resp, err := sendGetResp(c, "reserve\r\n")
	if err != nil {
		return nil, err
	}

	//parse response
	var id uint64
	var bodyLen int

	switch {
	case strings.Index(resp, "RESERVED") == 0:
		_, err = fmt.Sscanf(resp, "RESERVED %d %d\r\n", &id, &bodyLen)
		if err != nil {
			return nil, err
		}
	case resp == "DEADLINE_SOON\r\n":
		return nil, errDeadlineSoon
	case resp == "TIMED_OUT\r\n":
		return nil, errTimedOut
	default:
		return nil, parseCommonError(resp)
	}

	//read job body
	body := make([]byte, bodyLen+2) //+2 is for trailing \r\n
	n, err := io.ReadFull(c.reader, body)
	if err != nil {
		log.Println("failed reading body:", err.Error())
		return nil, err
	}

	body = body[:n-2] //strip \r\n trail

	return &Job{id, body}, nil
}

//Delete a job
func (c *Conn) Delete(id uint64) error {
	cmd := fmt.Sprintf("delete %d\r\n", id)
	expected := "DELETED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Use tube

The "use" command is for producers. Subsequent put commands will put jobs into
the tube specified by this command. If no use command has been issued, jobs
will be put into the tube named "default".
*/
func (c *Conn) Use(tubename string) error {
	//check parameter
	if len(tubename) > 200 {
		return errInvalidLen
	}

	cmd := fmt.Sprintf("use %s\r\n", tubename)
	expected := fmt.Sprintf("USING %s\r\n", tubename)
	return sendExpectExact(c, cmd, expected)
}

//Put job
func (c *Conn) Put(data []byte, pri, delay, ttr int) (uint64, error) {
	cmd := fmt.Sprintf("put %d %d %d %d\r\n", pri, delay, ttr, len(data))
	cmd = cmd + string(data) + "\r\n"

	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return 0, err
	}

	//parse Put response
	switch {
	case strings.Index(resp, "INSERTED") == 0:
		var id uint64
		_, parseErr := fmt.Sscanf(resp, "INSERTED %d\r\n", &id)
		return id, parseErr
	case strings.Index(resp, "BURIED") == 0:
		var id uint64
		fmt.Sscanf(resp, "BURIED %d\r\n", &id)
		return id, errBuried
	case resp == "EXPECTED_CRLF\r\n":
		return 0, errExpectedCrlf
	case resp == "JOB_TOO_BIG\r\n":
		return 0, errJobTooBig
	case resp == "DRAINING\r\n":
		return 0, errDraining
	default:
		return 0, parseCommonError(resp)
	}
	return 0, errUnknown
}

/*
Release a job.

The release command puts a reserved job back into the ready queue (and marks
its state as "ready") to be run by any client. It is normally used when the job
fails because of a transitory error.
	id is the job id to release.
	pri is a new priority to assign to the job.
	delay is an integer number of seconds to wait before putting the job in
		the ready queue. The job will be in the "delayed" state during this time.
*/
func (c *Conn) Release(id uint64, pri, delay int) error {
	cmd := fmt.Sprintf("release %d %d %d\r\n", id, pri, delay)
	expected := "RELEASED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Bury a job.

The bury command puts a job into the "buried" state. Buried jobs are put into a
FIFO linked list and will not be touched by the server again until a client
kicks them with the "kick" command.
	id is the job id to release.
	pri is a new priority to assign to the job.
*/
func (c *Conn) Bury(id uint64, pri int) error {
	cmd := fmt.Sprintf("bury %d %d\r\n", id, pri)
	expected := "BURIED\r\n"
	return sendExpectExact(c, cmd, expected)
}

/*
Touch a job

The "touch" command allows a worker to request more time to work on a job.
This is useful for jobs that potentially take a long time, but you still want
the benefits of a TTR pulling a job away from an unresponsive worker. A worker
may periodically tell the server that it's still alive and processing a job
(e.g. it may do this on DEADLINE_SOON)
*/
func (c *Conn) Touch(id uint64) error {
	cmd := fmt.Sprintf("touch %d\r\n", id)
	expected := "TOUCHED\r\n"
	return sendExpectExact(c, cmd, expected)
}

//send command and expect some exact response
func sendExpectExact(c *Conn, cmd, expected string) error {
	resp, err := sendGetResp(c, cmd)
	if err != nil {
		return err
	}

	if resp != expected {
		return parseCommonError(resp)
	}
	return nil
}

//Send command and read response
func sendGetResp(c *Conn, cmd string) (string, error) {
	_, err := c.conn.Write([]byte(cmd))
	if err != nil {
		return "", err
	}

	//wait for response
	resp, err := c.reader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return resp, nil
}

//parse for Common Error
func parseCommonError(str string) error {
	switch str {
	case "BURIED\r\n":
		return errBuried
	case "NOT_FOUND\r\n":
		return errNotFound
	case "OUT_OF_MEMORY\r\n":
		return errOutOfMemory
	case "INTERNAL_ERROR\r\n":
		return errInternalError
	case "BAD_FORMAT\r\n":
		return errBadFormat
	case "UNKNOWN_COMMAND\r\n":
		return errUnknownCommand
	}
	return errUnknown
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"math/big"
	"net"
	"os"
)

const PROB_PRIME_LIMIT int = 50
const DSS_P_MIN_LEN int = 512
const DSS_P_MAX_LEN int = 1024
const DSS_P_STRENGTH int = 64
const DSS_Q_LEN int = 160

// System Paramters
const sys_p string = "168199388701209853920129085113302407023173962717160229197318545484823101018386724351964316301278642143567435810448472465887143222934545154943005714265124445244247988777471773193847131514083030740407543233616696550197643519458134465700691569680905568000063025830089599260400096259430726498683087138415465107499"
const sys_q string = "959452661475451209325433595634941112150003865821"
const sys_g string = "94389192776327398589845326980349814526433869093412782345430946059206568804005181600855825906142967271872548375877738949875812540433223444968461350789461385043775029963900638123183435133537262152973355498432995364505138912569755859623649866375135353179362670798771770711847430626954864269888988371113567502852"

func checkParamValidity(dss_p *big.Int, dss_q *big.Int, dss_g *big.Int) int {

	p_check := (dss_p.ProbablyPrime(PROB_PRIME_LIMIT) && (dss_p.BitLen() >= DSS_P_MIN_LEN) && (dss_p.BitLen() <= DSS_P_MAX_LEN) && (dss_p.BitLen()%DSS_P_STRENGTH == 0))
	if !p_check {
		return 1
	}

	// FIXME: This is the correct way to use the big.Int package
	//(*big.Int).Mod(big.NewInt(0), big.NewInt(1), big.NewInt(2))
	// %s/big.NewInt(0) or otherdss.p/q/g/ / (*big.Int)

	q_check := ((dss_q.BitLen() == DSS_Q_LEN) && (dss_q.ProbablyPrime(PROB_PRIME_LIMIT)) &&
		(big.NewInt(0).Cmp((big.NewInt(0).Mod(big.NewInt(0).Sub(dss_p, big.NewInt(1)), dss_q))) == 0))
	if !q_check {
		return 1
	}

	g_check := (dss_g.Exp(dss_g, dss_q, dss_p).Cmp(big.NewInt(1)) == 0)
	if !g_check {
		return 1
	}

	return 0
}

func verifyCert(dss_r_str string, dss_s_str string, dss_h_str string, dss_g *big.Int, dss_p *big.Int, user_public_key_str string) int {
	dss_r := big.NewInt(0)
	dss_r.SetString(dss_r_str, 10)

	dss_s := big.NewInt(0)
	dss_s.SetString(dss_s_str, 10)

	dss_h := big.NewInt(0)
	dss_h.SetString(dss_h_str, 10)

	sys_q_bigInt := big.NewInt(0)
	sys_q_bigInt.SetString(sys_q, 10)

	user_public_key := big.NewInt(0)
	user_public_key.SetString(user_public_key_str, 10)

	if (dss_r.Cmp(big.NewInt(0)) == 1) && (dss_r.Cmp(sys_q_bigInt) == -1) && (dss_r.Cmp(big.NewInt(0)) == 1) && (dss_s.Cmp(sys_q_bigInt) == -1) {
		dss_u := new(big.Int).Mod((new(big.Int).Mul(dss_h, new(big.Int).ModInverse(dss_s, sys_q_bigInt))), sys_q_bigInt)

		dss_v := new(big.Int).Mod(new(big.Int).Mul(dss_r, new(big.Int).ModInverse(dss_s, sys_q_bigInt)), sys_q_bigInt)

		dss_w := new(big.Int).Mul(new(big.Int).Exp(dss_g, dss_u, dss_p), new(big.Int).Exp(user_public_key, dss_v, dss_p))
		dss_w = new(big.Int).Mod(dss_w, dss_p)
		dss_w = new(big.Int).Mod(dss_w, sys_q_bigInt)

		if dss_w.Cmp(dss_r) == 0 {
			return 0
		} else {
			fmt.Println("dss_r: ", dss_r)
			fmt.Println("sys_q_bigInt: ", sys_q_bigInt)
			fmt.Println("dss_s: ", dss_s)
			fmt.Println("dss_h: ", dss_h)
			fmt.Println("dss_u: ", dss_u)
			fmt.Println("dss_v: ", dss_v)
			fmt.Println("dss_w: ", dss_w)
			fmt.Println("dss_r: ", dss_r)
		}
	}

	return -1
}

func main() {
	dss_p := big.NewInt(0)
	dss_p.SetString(sys_p, 10)

	dss_q := big.NewInt(0)
	dss_q.SetString(sys_q, 10)

	dss_g := big.NewInt(0)
	dss_g.SetString(sys_g, 10)

	if checkParamValidity(dss_p, dss_q, dss_g) != 0 {
		fmt.Println("The selection of either p, q, or g doesn't meet the DSS requirement")
		fmt.Println("Exiting...")
		os.Exit(1)
	}

	connection, _ := net.Dial("tcp", "localhost:8081")
	reader := bufio.NewReader(os.Stdin)

	fmt.Print("Enter the user identity: ")
	user_id, _ := reader.ReadString('\n')
	fmt.Fprintf(connection, user_id+"\n")

	fmt.Print("Enter the user's public key: ")
	user_public_key, _ := reader.ReadString('\n')
	fmt.Fprintf(connection, user_public_key+"\n")

	// Receive stuff from goca-server
	dss_r_str, _ := bufio.NewReader(connection).ReadString('\n')
	dss_s_str, _ := bufio.NewReader(connection).ReadString('\n')
	user_public_key_str, _ := bufio.NewReader(connection).ReadString('\n')
	expDate_str, _ := bufio.NewReader(connection).ReadString('\n')
	dss_h_str, _ := bufio.NewReader(connection).ReadString('\n')

	if verifyCert(dss_r_str, dss_s_str, dss_h_str, dss_g, dss_p, user_public_key_str) == 0 {
		fmt.Println("DSS Certificate is Valid!")
		fmt.Printf("dss_r = %v", dss_r_str)
		fmt.Printf("dss_s = %v\n", dss_s_str)
		fmt.Printf("user_public_key_str = %v\n", user_public_key_str)
		fmt.Printf("expiry date = %v\n", expDate_str)
		fmt.Printf("dss_hash = %v\n", dss_h_str)
	} else {
		fmt.Println("DSS Certificate is invalid!")
		fmt.Println("dss_r_str: ", dss_r_str)
		fmt.Println("dss_s_str: ", dss_s_str)
		fmt.Println("user_public_key: ", user_public_key)
		fmt.Println("expDate_str: ", expDate_str)
		fmt.Println("dss_h_str: ", dss_h_str)
	}
}
<commit_msg>better usage<commit_after>package main

import (
	"bufio"
	"fmt"
	"math/big"
	"net"
	"os"
)

const PROB_PRIME_LIMIT int = 50
const DSS_P_MIN_LEN int = 512
const DSS_P_MAX_LEN int = 1024
const DSS_P_STRENGTH int = 64
const DSS_Q_LEN int = 160

// User Public Key
const SK_USER string = "432398415306986194693973996870836079581453988813"

// System Paramters
const sys_p string = "168199388701209853920129085113302407023173962717160229197318545484823101018386724351964316301278642143567435810448472465887143222934545154943005714265124445244247988777471773193847131514083030740407543233616696550197643519458134465700691569680905568000063025830089599260400096259430726498683087138415465107499"
const sys_q string = "959452661475451209325433595634941112150003865821"
const sys_g string = "94389192776327398589845326980349814526433869093412782345430946059206568804005181600855825906142967271872548375877738949875812540433223444968461350789461385043775029963900638123183435133537262152973355498432995364505138912569755859623649866375135353179362670798771770711847430626954864269888988371113567502852"

func checkParamValidity(dss_p *big.Int, dss_q *big.Int, dss_g *big.Int) int {

	p_check := (dss_p.ProbablyPrime(PROB_PRIME_LIMIT) && (dss_p.BitLen() >= DSS_P_MIN_LEN) && (dss_p.BitLen() <= DSS_P_MAX_LEN) && (dss_p.BitLen()%DSS_P_STRENGTH == 0))
	if !p_check {
		return 1
	}

	q_check := ((dss_q.BitLen() == DSS_Q_LEN) && (dss_q.ProbablyPrime(PROB_PRIME_LIMIT)) &&
		(new(big.Int).Cmp(new(big.Int).Mod(new(big.Int).Sub(dss_p, big.NewInt(1)), dss_q))) == 0)
	if !q_check {
		return 1
	}

	g_check := (new(big.Int).Exp(dss_g, dss_q, dss_p).Cmp(big.NewInt(1)) == 0)
	if !g_check {
		return 1
	}

	return 0
}

func verifyCert(dss_r_str string, dss_s_str string, dss_h_str string, dss_g *big.Int, dss_p *big.Int) int {
	dss_r := big.NewInt(0)
	dss_r.SetString(dss_r_str, 10)

	dss_s := big.NewInt(0)
	dss_s.SetString(dss_s_str, 10)

	dss_h := big.NewInt(0)
	dss_h.SetString(dss_h_str, 10)

	sys_q_bigInt := big.NewInt(0)
	sys_q_bigInt.SetString(sys_q, 10)

	user_public_key := big.NewInt(0)
	user_public_key.SetString(SK_USER, 10)

	if (dss_r.Cmp(big.NewInt(0)) == 1) && (dss_r.Cmp(sys_q_bigInt) == -1) && (dss_r.Cmp(big.NewInt(0)) == 1) && (dss_s.Cmp(sys_q_bigInt) == -1) {
		dss_u := new(big.Int).Mod((new(big.Int).Mul(dss_h, new(big.Int).ModInverse(dss_s, sys_q_bigInt))), sys_q_bigInt)

		dss_v := new(big.Int).Mod(new(big.Int).Mul(dss_r, new(big.Int).ModInverse(dss_s, sys_q_bigInt)), sys_q_bigInt)

		dss_w := new(big.Int).Exp(dss_g, dss_u, dss_p)
		fmt.Println("dss_w: ", dss_w)
		dss_w = new(big.Int).Mul(dss_w, new(big.Int).Exp(user_public_key, dss_v, dss_p))
		dss_w = new(big.Int).Mod(dss_w, dss_p)
		dss_w = new(big.Int).Mod(dss_w, sys_q_bigInt)
		fmt.Println("dss_w: ", dss_w)

		if dss_w.Cmp(dss_r) == 0 {
			return 0
		} else {
			fmt.Println("dss_r: ", dss_r)
			fmt.Println("sys_q_bigInt: ", sys_q_bigInt)
			fmt.Println("dss_s: ", dss_s)
			fmt.Println("dss_h: ", dss_h)
			fmt.Println("dss_u: ", dss_u)
			fmt.Println("dss_v: ", dss_v)
			fmt.Println("dss_w: ", dss_w)
			fmt.Println("dss_r: ", dss_r)
		}
	}

	return -1
}

func main() {
	dss_p := big.NewInt(0)
	dss_p.SetString(sys_p, 10)

	dss_q := big.NewInt(0)
	dss_q.SetString(sys_q, 10)

	dss_g := big.NewInt(0)
	dss_g.SetString(sys_g, 10)

	if checkParamValidity(dss_p, dss_q, dss_g) != 0 {
		fmt.Println("The selection of either p, q, or g doesn't meet the DSS requirement")
		fmt.Println("Exiting...")
		os.Exit(1)
	}

	connection, _ := net.Dial("tcp", "localhost:8081")
	reader := bufio.NewReader(os.Stdin)

	fmt.Print("Enter the user identity: ")
	user_id, _ := reader.ReadString('\n')
	fmt.Fprintf(connection, user_id+"\n")

	fmt.Print("Public key OK? [", SK_USER, "]: Press Enter to accept.")
	reader.ReadString('\n')
	fmt.Fprintf(connection, SK_USER+"\n")

	// Receive stuff from goca-server
	dss_r_str, _ := bufio.NewReader(connection).ReadString('\n')
	dss_s_str, _ := bufio.NewReader(connection).ReadString('\n')
	user_public_key_str, _ := bufio.NewReader(connection).ReadString('\n')
	expDate_str, _ := bufio.NewReader(connection).ReadString('\n')
	dss_h_str, _ := bufio.NewReader(connection).ReadString('\n')

	if verifyCert(dss_r_str, dss_s_str, dss_h_str, dss_g, dss_p) == 0 {
		fmt.Println("DSS Certificate is Valid!")
		fmt.Printf("dss_r = %v", dss_r_str)
		fmt.Printf("dss_s = %v\n", dss_s_str)
		fmt.Printf("user_public_key_str = %v\n", user_public_key_str)
		fmt.Printf("expiry date = %v\n", expDate_str)
		fmt.Printf("dss_hash = %v\n", dss_h_str)
	} else {
		fmt.Println("DSS Certificate is invalid!")
		fmt.Println("dss_r_str: ", dss_r_str)
		fmt.Println("dss_s_str: ", dss_s_str)
		fmt.Println("user_public_key: ", SK_USER)
		fmt.Println("expDate_str: ", expDate_str)
		fmt.Println("dss_h_str: ", dss_h_str)
	}
}
<|endoftext|>