<commit_before>/*
Copyright 2016 caicloud authors. All rights reserved.

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 vcs

import (
	"fmt"
	"strings"

	"github.com/caicloud/cyclone/api"
	"github.com/caicloud/cyclone/pkg/log"
	"github.com/caicloud/cyclone/pkg/pathutil"
	steplog "github.com/caicloud/cyclone/worker/log"
	"github.com/caicloud/cyclone/worker/vcs/provider"
)

// Manager manages all version control operations, like clone, cherry-pick.
// Based on the operations, some are handled asychronously and some are not.
// Asynchronous operations are time consuming and usually involve stream output
// to clients, like clone, fetch, etc; synchronous operations are not time
// consuming and usually don't have to send output, like checkout a tag, etc.
// The above constants define all async operations; all other operations are
// synchronous. Manager is also responsible for managing repository status;
// it knows whether a repository is healthy or not, and set repository status
// accordingly.
// synchronous.
type Manager struct {
}

// NewManager creates a new Manager.
func NewManager() *Manager {
	return &Manager{}
}

// This function is used to insert the string "insertion" into the "url"
// at the "index" postiion
func insert(url, insertion string, index int) string {
	result := make([]byte, len(url)+len(insertion))
	slice := []byte(url)
	at := copy(result, slice[:index])
	at += copy(result[at:], insertion)
	copy(result[at:], slice[index:])
	return string(result)
}

func getUrlwithToken(url, subvcs, token string) string {
	switch subvcs {
	case api.GITHUB:
		position := strings.Index(url, "github.com")
		url = insert(url, token+"@", position)
	case api.GITLAB:
		if strings.HasPrefix(url, "http://") {
			position := len("http://")
			url = insert(url, "oauth2:"+token+"@", position)
		} else if strings.HasPrefix(url, "https://") {
			position := len("https://")
			url = insert(url, "oauth2:"+token+"@", position)
		}
	default:
	}
	return url
}

// CloneServiceRepository clones a service's repo and records service status accordingly.
func (vm *Manager) CloneServiceRepository(event *api.Event) error {
	// Get the path to store cloned repository.
	destPath := vm.GetCloneDir(&event.Service, &event.Version)
	if err := pathutil.EnsureParentDir(destPath, 0750); err != nil {
		event.Service.Repository.Status = api.RepositoryInternalError
		return fmt.Errorf("Unable to create parent directory for %s: %v\n", destPath, err)
	}

	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		event.Service.Repository.Status = api.RepositoryUnknownVcs
		return fmt.Errorf("Unable to write to event output for event: %v\n", err)
	}

	url := getUrlwithToken(event.Service.Repository.URL, event.Service.Repository.SubVcs, event.Data["Token"].(string))
	if err := worker.CloneRepo(url, destPath, event); err != nil {
		event.Service.Repository.Status = api.RepositoryMissing
		return fmt.Errorf("Unable to clone repository for service: %v\n", err)
	}

	// Happy path - update status to healthy and return nil error. Database status
	// will be updated via defer function. If we encounter error during database
	// update, repository status will be set to internal error.
	event.Service.Repository.Status = api.RepositoryHealthy
	return nil
}

// CloneVersionRepository clones a version's repo
func (vm *Manager) CloneVersionRepository(event *api.Event) error {
	// Get the path to store cloned repository.
	destPath := vm.GetCloneDir(&event.Service, &event.Version)
	if err := pathutil.EnsureParentDir(destPath, 0750); err != nil {
		return fmt.Errorf("Unable to create parent directory for %s: %v\n", destPath, err)
	}

	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		return fmt.Errorf("Unable to write to event output for event: %v\n", err)
	}

	url := getUrlwithToken(event.Version.URL, event.Service.Repository.SubVcs, event.Data["Token"].(string))
	steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Start, nil)
	if err := worker.CloneRepo(url, destPath, event); err != nil {
		steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Stop, err)
		return fmt.Errorf("Unable to clone repository for version: %v\n", err)
	}
	// create version call by UI API, the commit is empty
	// create version call by webhook, the commit is not empty
	if "" == event.Version.Commit {
		// set version commit
		if commit, err := worker.GetTagCommit(destPath, "master"); err != nil {
			log.Error("cannot get tag commit")
		} else {
			// write to DB in posthook
			event.Version.Commit = commit
		}
	} else {
		// checkout special commit
		if err = worker.CheckOutByCommitID(event.Version.Commit, destPath, event); err != nil {
			event.Service.Repository.Status = api.RepositoryMissing
			steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Stop, err)
			return fmt.Errorf("Unable to check out commit %s :%v\n", event.Version.Commit, err)
		}
	}

	if api.APIOperator == event.Version.Operator {
		// create tag
		if err := worker.NewTagFromLatest(destPath, event); err != nil {
			log.Errorf("Unable to push new commit %s :%v\n", event.Version.Commit, err)
		}
	}
	steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Finish, nil)
	return nil
}

// NewTagFromLatest creates a new tag from latest source for a service.
func (vm *Manager) NewTagFromLatest(event *api.Event) error {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		return fmt.Errorf("Unable to checkout latest source %#+v: %v", event.Service, err)
	}

	// Do the actual work.
	repositoryPath := vm.GetCloneDir(&event.Service, &event.Version)
	err = worker.NewTagFromLatest(repositoryPath, event)
	if err != nil {
		return fmt.Errorf("Unable to create tag for service %#+v: %v\n", event.Service, err)
	}
	return nil
}

// CheckoutTag checkout to given tag in version.
func (vm *Manager) CheckoutTag(service *api.Service, version *api.Version) error {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(service)
	if err != nil {
		return err
	}

	err = worker.CheckoutTag(vm.GetCloneDir(service, version), version.Name)
	if err != nil {
		return fmt.Errorf("Unable to checkout tag for service %#+v: %v\n", service, err)
	}
	return nil
}

// GetTagCommit finds commit/revision hash of a given tag.
func (vm *Manager) GetTagCommit(service *api.Service, version *api.Version) (string, error) {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(service)
	if err != nil {
		return "", err
	}

	commit, err := worker.GetTagCommit(vm.GetCloneDir(service, version), version.Name)
	if err != nil {
		return "", err
	}
	return commit, nil
}

// GetCloneDir returns the directory where a repository should be cloned to. It honors
// flag 'cloneDir' which is primarily used for testing/debugging. We use the combination
// of cloneDir, userID, serviceID, and versionID as repository path. As repositories come
// and go, we don't have to have a persistent directory structure; therefore, if version
// is not nil, use cloneDir/userID/versionID; otherwise, use cloneDir/userID/serviceID.
func (vm *Manager) GetCloneDir(service *api.Service, version *api.Version) string {
	if version.VersionID == "" {
		return fmt.Sprintf("/%s/%s", service.UserID, service.ServiceID)
	} else {
		return fmt.Sprintf("/%s/%s", service.UserID, version.VersionID)
	}
}

// findVcsForService is a helper method which finds the VCS worker based on service spec.
func (vm *Manager) findVcsForService(service *api.Service) (VCS, error) {
	switch service.Repository.Vcs {
	case api.Git:
		return &provider.Git{}, nil
	case api.Svn:
		return &provider.Svn{}, nil
	case api.Fake:
		return provider.NewFake(service.Repository.URL)
	default:
		return nil, fmt.Errorf("Unknown version control system %s", service.Repository.Vcs)
	}
}
<commit_msg>increase the check to prevent crashes<commit_after>/*
Copyright 2016 caicloud authors. All rights reserved.

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 vcs

import (
	"fmt"
	"strings"

	"github.com/caicloud/cyclone/api"
	"github.com/caicloud/cyclone/pkg/log"
	"github.com/caicloud/cyclone/pkg/pathutil"
	steplog "github.com/caicloud/cyclone/worker/log"
	"github.com/caicloud/cyclone/worker/vcs/provider"
)

// Manager manages all version control operations, like clone, cherry-pick.
// Based on the operations, some are handled asychronously and some are not.
// Asynchronous operations are time consuming and usually involve stream output
// to clients, like clone, fetch, etc; synchronous operations are not time
// consuming and usually don't have to send output, like checkout a tag, etc.
// The above constants define all async operations; all other operations are
// synchronous. Manager is also responsible for managing repository status;
// it knows whether a repository is healthy or not, and set repository status
// accordingly.
// synchronous.
type Manager struct {
}

// NewManager creates a new Manager.
func NewManager() *Manager {
	return &Manager{}
}

// This function is used to insert the string "insertion" into the "url"
// at the "index" postiion
func insert(url, insertion string, index int) string {
	result := make([]byte, len(url)+len(insertion))
	slice := []byte(url)
	at := copy(result, slice[:index])
	at += copy(result[at:], insertion)
	copy(result[at:], slice[index:])
	return string(result)
}

func getUrlwithToken(url, subvcs, token string) string {
	switch subvcs {
	case api.GITHUB:
		if token == "" {
			log.Warn("subvcs is github, but the token is empty, there meybe exist error")
			break
		}
		position := strings.Index(url, "github.com")
		if position == -1 {
			log.Warn("subvcs is github and the token is not empty, but the url dosen't contain github.com")
			break
		}
		url = insert(url, token+"@", position)
	case api.GITLAB:
		if token == "" {
			log.Warn("subvcs is gitlab, but the token is empty, there meybe exist error")
			break
		}
		if strings.HasPrefix(url, "http://") {
			position := len("http://")
			url = insert(url, "oauth2:"+token+"@", position)
		} else if strings.HasPrefix(url, "https://") {
			position := len("https://")
			url = insert(url, "oauth2:"+token+"@", position)
		}
	default:
	}
	return url
}

// CloneServiceRepository clones a service's repo and records service status accordingly.
func (vm *Manager) CloneServiceRepository(event *api.Event) error {
	// Get the path to store cloned repository.
	destPath := vm.GetCloneDir(&event.Service, &event.Version)
	if err := pathutil.EnsureParentDir(destPath, 0750); err != nil {
		event.Service.Repository.Status = api.RepositoryInternalError
		return fmt.Errorf("Unable to create parent directory for %s: %v\n", destPath, err)
	}

	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		event.Service.Repository.Status = api.RepositoryUnknownVcs
		return fmt.Errorf("Unable to write to event output for event: %v\n", err)
	}

	url := getUrlwithToken(event.Service.Repository.URL, event.Service.Repository.SubVcs, event.Data["Token"].(string))
	if err := worker.CloneRepo(url, destPath, event); err != nil {
		event.Service.Repository.Status = api.RepositoryMissing
		return fmt.Errorf("Unable to clone repository for service: %v\n", err)
	}

	// Happy path - update status to healthy and return nil error. Database status
	// will be updated via defer function. If we encounter error during database
	// update, repository status will be set to internal error.
	event.Service.Repository.Status = api.RepositoryHealthy
	return nil
}

// CloneVersionRepository clones a version's repo
func (vm *Manager) CloneVersionRepository(event *api.Event) error {
	// Get the path to store cloned repository.
	destPath := vm.GetCloneDir(&event.Service, &event.Version)
	if err := pathutil.EnsureParentDir(destPath, 0750); err != nil {
		return fmt.Errorf("Unable to create parent directory for %s: %v\n", destPath, err)
	}

	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		return fmt.Errorf("Unable to write to event output for event: %v\n", err)
	}

	url := getUrlwithToken(event.Version.URL, event.Service.Repository.SubVcs, event.Data["Token"].(string))
	steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Start, nil)
	if err := worker.CloneRepo(url, destPath, event); err != nil {
		steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Stop, err)
		return fmt.Errorf("Unable to clone repository for version: %v\n", err)
	}
	// create version call by UI API, the commit is empty
	// create version call by webhook, the commit is not empty
	if "" == event.Version.Commit {
		// set version commit
		if commit, err := worker.GetTagCommit(destPath, "master"); err != nil {
			log.Error("cannot get tag commit")
		} else {
			// write to DB in posthook
			event.Version.Commit = commit
		}
	} else {
		// checkout special commit
		if err = worker.CheckOutByCommitID(event.Version.Commit, destPath, event); err != nil {
			event.Service.Repository.Status = api.RepositoryMissing
			steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Stop, err)
			return fmt.Errorf("Unable to check out commit %s :%v\n", event.Version.Commit, err)
		}
	}

	if api.APIOperator == event.Version.Operator {
		// create tag
		if err := worker.NewTagFromLatest(destPath, event); err != nil {
			log.Errorf("Unable to push new commit %s :%v\n", event.Version.Commit, err)
		}
	}
	steplog.InsertStepLog(event, steplog.CloneRepository, steplog.Finish, nil)
	return nil
}

// NewTagFromLatest creates a new tag from latest source for a service.
func (vm *Manager) NewTagFromLatest(event *api.Event) error {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(&event.Service)
	if err != nil {
		return fmt.Errorf("Unable to checkout latest source %#+v: %v", event.Service, err)
	}

	// Do the actual work.
	repositoryPath := vm.GetCloneDir(&event.Service, &event.Version)
	err = worker.NewTagFromLatest(repositoryPath, event)
	if err != nil {
		return fmt.Errorf("Unable to create tag for service %#+v: %v\n", event.Service, err)
	}
	return nil
}

// CheckoutTag checkout to given tag in version.
func (vm *Manager) CheckoutTag(service *api.Service, version *api.Version) error {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(service)
	if err != nil {
		return err
	}

	err = worker.CheckoutTag(vm.GetCloneDir(service, version), version.Name)
	if err != nil {
		return fmt.Errorf("Unable to checkout tag for service %#+v: %v\n", service, err)
	}
	return nil
}

// GetTagCommit finds commit/revision hash of a given tag.
func (vm *Manager) GetTagCommit(service *api.Service, version *api.Version) (string, error) {
	// Find version control system worker and return if error occurs.
	worker, err := vm.findVcsForService(service)
	if err != nil {
		return "", err
	}

	commit, err := worker.GetTagCommit(vm.GetCloneDir(service, version), version.Name)
	if err != nil {
		return "", err
	}
	return commit, nil
}

// GetCloneDir returns the directory where a repository should be cloned to. It honors
// flag 'cloneDir' which is primarily used for testing/debugging. We use the combination
// of cloneDir, userID, serviceID, and versionID as repository path. As repositories come
// and go, we don't have to have a persistent directory structure; therefore, if version
// is not nil, use cloneDir/userID/versionID; otherwise, use cloneDir/userID/serviceID.
func (vm *Manager) GetCloneDir(service *api.Service, version *api.Version) string {
	if version.VersionID == "" {
		return fmt.Sprintf("/%s/%s", service.UserID, service.ServiceID)
	}
	return fmt.Sprintf("/%s/%s", service.UserID, version.VersionID)
}

// findVcsForService is a helper method which finds the VCS worker based on service spec.
func (vm *Manager) findVcsForService(service *api.Service) (VCS, error) {
	switch service.Repository.Vcs {
	case api.Git:
		return &provider.Git{}, nil
	case api.Svn:
		return &provider.Svn{}, nil
	case api.Fake:
		return provider.NewFake(service.Repository.URL)
	default:
		return nil, fmt.Errorf("Unknown version control system %s", service.Repository.Vcs)
	}
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package ramledger

import (
	"bytes"
	"sync"

	"github.com/hyperledger/fabric/common/flogging"
	"github.com/hyperledger/fabric/common/ledger/blockledger"
	cb "github.com/hyperledger/fabric/protos/common"
	ab "github.com/hyperledger/fabric/protos/orderer"
	"github.com/pkg/errors"
)

const pkgLogID = "orderer/ledger/ramledger"

var logger = flogging.MustGetLogger(pkgLogID)

type cursor struct {
	list *simpleList
}

type simpleList struct {
	next   *simpleList
	signal chan struct{}
	block  *cb.Block
}

type ramLedger struct {
	lock    sync.RWMutex
	maxSize int
	size    int
	oldest  *simpleList
	newest  *simpleList
}

// Next blocks until there is a new block available, or returns an error if the
// next block is no longer retrievable
func (cu *cursor) Next() (*cb.Block, cb.Status) {
	// This only loops once, as signal reading indicates non-nil next
	for {
		if cu.list.next != nil {
			cu.list = cu.list.next
			return cu.list.block, cb.Status_SUCCESS
		}
		<-cu.list.signal
	}
}

// Close does nothing
func (cu *cursor) Close() {}

// Iterator returns an Iterator, as specified by a ab.SeekInfo message, and its
// starting block number
func (rl *ramLedger) Iterator(startPosition *ab.SeekPosition) (blockledger.Iterator, uint64) {
	rl.lock.RLock()
	defer rl.lock.RUnlock()

	var list *simpleList
	switch start := startPosition.Type.(type) {
	case *ab.SeekPosition_Oldest:
		oldest := rl.oldest
		list = &simpleList{
			block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
			next:   oldest,
			signal: make(chan struct{}),
		}
		close(list.signal)
	case *ab.SeekPosition_Newest:
		newest := rl.newest
		list = &simpleList{
			block:  &cb.Block{Header: &cb.BlockHeader{Number: newest.block.Header.Number - 1}},
			next:   newest,
			signal: make(chan struct{}),
		}
		close(list.signal)
	case *ab.SeekPosition_Specified:
		oldest := rl.oldest
		specified := start.Specified.Number
		logger.Debugf("Attempting to return block %d", specified)

		// Note the two +1's here is to accommodate the 'preGenesis' block of ^uint64(0)
		if specified+1 < oldest.block.Header.Number+1 || specified > rl.newest.block.Header.Number+1 {
			logger.Debugf("Returning error iterator because specified seek was %d with oldest %d and newest %d",
				specified, rl.oldest.block.Header.Number, rl.newest.block.Header.Number)
			return &blockledger.NotFoundErrorIterator{}, 0
		}

		if specified == oldest.block.Header.Number {
			list = &simpleList{
				block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
				next:   oldest,
				signal: make(chan struct{}),
			}
			close(list.signal)
			break
		}

		list = oldest
		for {
			if list.block.Header.Number == specified-1 {
				break
			}
			list = list.next // No need for nil check, because of range check above
		}
	}
	cursor := &cursor{list: list}
	blockNum := list.block.Header.Number + 1

	// If the cursor is for pre-genesis, skip it, the block number wraps
	if blockNum == ^uint64(0) {
		cursor.Next()
		blockNum++
	}

	return cursor, blockNum
}

// Height returns the number of blocks on the ledger
func (rl *ramLedger) Height() uint64 {
	rl.lock.RLock()
	defer rl.lock.RUnlock()
	return rl.newest.block.Header.Number + 1
}

// Append appends a new block to the ledger
func (rl *ramLedger) Append(block *cb.Block) error {
	rl.lock.Lock()
	defer rl.lock.Unlock()

	if block.Header.Number != rl.newest.block.Header.Number+1 {
		return errors.Errorf("block number should have been %d but was %d",
			rl.newest.block.Header.Number+1, block.Header.Number)
	}

	if rl.newest.block.Header.Number+1 != 0 { // Skip this check for genesis block insertion
		if !bytes.Equal(block.Header.PreviousHash, rl.newest.block.Header.Hash()) {
			return errors.Errorf("block should have had previous hash of %x but was %x",
				rl.newest.block.Header.Hash(), block.Header.PreviousHash)
		}
	}

	rl.appendBlock(block)
	return nil
}

func (rl *ramLedger) appendBlock(block *cb.Block) {
	rl.newest.next = &simpleList{
		signal: make(chan struct{}),
		block:  block,
	}

	lastSignal := rl.newest.signal
	logger.Debugf("Sending signal that block %d has a successor", rl.newest.block.Header.Number)
	rl.newest = rl.newest.next
	close(lastSignal)

	rl.size++

	if rl.size > rl.maxSize {
		logger.Debugf("RAM ledger max size about to be exceeded, removing oldest item: %d",
			rl.oldest.block.Header.Number)
		rl.oldest = rl.oldest.next
		rl.size--
	}
}
<commit_msg>[FAB-11684] serialization in ram ledger simpleList<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package ramledger

import (
	"bytes"
	"sync"

	"github.com/hyperledger/fabric/common/flogging"
	"github.com/hyperledger/fabric/common/ledger/blockledger"
	cb "github.com/hyperledger/fabric/protos/common"
	ab "github.com/hyperledger/fabric/protos/orderer"
	"github.com/pkg/errors"
)

const pkgLogID = "orderer/ledger/ramledger"

var logger = flogging.MustGetLogger(pkgLogID)

type cursor struct {
	list *simpleList
}

type simpleList struct {
	lock   sync.RWMutex
	next   *simpleList
	signal chan struct{}
	block  *cb.Block
}

func (s *simpleList) getNext() *simpleList {
	s.lock.RLock()
	defer s.lock.RUnlock()
	return s.next
}

func (s *simpleList) setNext(n *simpleList) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.next = n
}

type ramLedger struct {
	lock    sync.RWMutex
	maxSize int
	size    int
	oldest  *simpleList
	newest  *simpleList
}

// Next blocks until there is a new block available, or returns an error if the
// next block is no longer retrievable
func (cu *cursor) Next() (*cb.Block, cb.Status) {
	// This only loops once, as signal reading indicates non-nil next
	for {
		next := cu.list.getNext()
		if next != nil {
			cu.list = next
			return cu.list.block, cb.Status_SUCCESS
		}
		<-cu.list.signal
	}
}

// Close does nothing
func (cu *cursor) Close() {}

// Iterator returns an Iterator, as specified by a ab.SeekInfo message, and its
// starting block number
func (rl *ramLedger) Iterator(startPosition *ab.SeekPosition) (blockledger.Iterator, uint64) {
	rl.lock.RLock()
	defer rl.lock.RUnlock()

	var list *simpleList
	switch start := startPosition.Type.(type) {
	case *ab.SeekPosition_Oldest:
		oldest := rl.oldest
		list = &simpleList{
			block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
			next:   oldest,
			signal: make(chan struct{}),
		}
		close(list.signal)
	case *ab.SeekPosition_Newest:
		newest := rl.newest
		list = &simpleList{
			block:  &cb.Block{Header: &cb.BlockHeader{Number: newest.block.Header.Number - 1}},
			next:   newest,
			signal: make(chan struct{}),
		}
		close(list.signal)
	case *ab.SeekPosition_Specified:
		oldest := rl.oldest
		specified := start.Specified.Number
		logger.Debugf("Attempting to return block %d", specified)

		// Note the two +1's here is to accommodate the 'preGenesis' block of ^uint64(0)
		if specified+1 < oldest.block.Header.Number+1 || specified > rl.newest.block.Header.Number+1 {
			logger.Debugf("Returning error iterator because specified seek was %d with oldest %d and newest %d",
				specified, rl.oldest.block.Header.Number, rl.newest.block.Header.Number)
			return &blockledger.NotFoundErrorIterator{}, 0
		}

		if specified == oldest.block.Header.Number {
			list = &simpleList{
				block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
				next:   oldest,
				signal: make(chan struct{}),
			}
			close(list.signal)
			break
		}

		list = oldest
		for {
			if list.block.Header.Number == specified-1 {
				break
			}
			list = list.getNext() // No need for nil check, because of range check above
		}
	}
	cursor := &cursor{list: list}
	blockNum := list.block.Header.Number + 1

	// If the cursor is for pre-genesis, skip it, the block number wraps
	if blockNum == ^uint64(0) {
		cursor.Next()
		blockNum++
	}

	return cursor, blockNum
}

// Height returns the number of blocks on the ledger
func (rl *ramLedger) Height() uint64 {
	rl.lock.RLock()
	defer rl.lock.RUnlock()
	return rl.newest.block.Header.Number + 1
}

// Append appends a new block to the ledger
func (rl *ramLedger) Append(block *cb.Block) error {
	rl.lock.Lock()
	defer rl.lock.Unlock()

	if block.Header.Number != rl.newest.block.Header.Number+1 {
		return errors.Errorf("block number should have been %d but was %d",
			rl.newest.block.Header.Number+1, block.Header.Number)
	}

	if rl.newest.block.Header.Number+1 != 0 { // Skip this check for genesis block insertion
		if !bytes.Equal(block.Header.PreviousHash, rl.newest.block.Header.Hash()) {
			return errors.Errorf("block should have had previous hash of %x but was %x",
				rl.newest.block.Header.Hash(), block.Header.PreviousHash)
		}
	}

	rl.appendBlock(block)
	return nil
}

func (rl *ramLedger) appendBlock(block *cb.Block) {
	next := &simpleList{
		signal: make(chan struct{}),
		block:  block,
	}
	rl.newest.setNext(next)

	lastSignal := rl.newest.signal
	logger.Debugf("Sending signal that block %d has a successor", rl.newest.block.Header.Number)
	rl.newest = rl.newest.getNext()
	close(lastSignal)

	rl.size++

	if rl.size > rl.maxSize {
		logger.Debugf("RAM ledger max size about to be exceeded, removing oldest item: %d",
			rl.oldest.block.Header.Number)
		rl.oldest = rl.oldest.getNext()
		rl.size--
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"
	//"fmt"
)

var p Parser
var email EmailNotifier
var lastProblems []Problem
var notifiers []Notifier
var apiClient APIClient

func main() {
	p.Parse("/home/niklas/GO/src/github.com/KIT-MAMID/mamid/notifier/contacts.txt")
	notifiers = append(notifiers, &email)
	// Wait forever
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	//receive Problems through API
	var currentProblems []Problem = apiClient.Receive("localhost:8080")
	currentProblems = diffProblems(currentProblems)
	for i := 0; i < len(currentProblems); i++ {
		print(currentProblems[i].Description)
		notify(currentProblems[i])
	}
	<-c
	os.Exit(0)

}
func diffProblems(received []Problem) []Problem {
	for i := 0; i < len(received); i++ {
		for j := 0; j < len(lastProblems); j++ {
			if true {
				received = append(received[:i], received[i+1:]...)
			}
		}
	}
	return received
}

func notify(problem Problem) {
	for i := 0; i < len(notifiers); i++ {
		notifiers[i].SendProblem(problem)
	}
}
<commit_msg>FIX: read contacts.txt relative to controller<commit_after>package main

import (
	"os"
	"os/signal"
	//"fmt"
)

var p Parser
var email EmailNotifier
var lastProblems []Problem
var notifiers []Notifier
var apiClient APIClient

func main() {
	p.Parse("contacts.txt")
	notifiers = append(notifiers, &email)
	// Wait forever
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	//receive Problems through API
	var currentProblems []Problem = apiClient.Receive("localhost:8080")
	currentProblems = diffProblems(currentProblems)
	for i := 0; i < len(currentProblems); i++ {
		print(currentProblems[i].Description)
		notify(currentProblems[i])
	}
	<-c
	os.Exit(0)

}
func diffProblems(received []Problem) []Problem {
	for i := 0; i < len(received); i++ {
		for j := 0; j < len(lastProblems); j++ {
			if true {
				received = append(received[:i], received[i+1:]...)
			}
		}
	}
	return received
}

func notify(problem Problem) {
	for i := 0; i < len(notifiers); i++ {
		notifiers[i].SendProblem(problem)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy_header

import (
    "crypto/rand"
    "errors"
    "fmt"
    "strings"

    "sippy/net"
    "sippy/utils"
)

type SipWWWAuthenticateBody struct {
    realm *sippy_net.MyAddress
    nonce string
}

type SipWWWAuthenticate struct {
    normalName
    string_body     string
    body            *SipWWWAuthenticateBody
}

var _sip_www_authenticate_name normalName = newNormalName("WWW-Authenticate")

func CreateSipWWWAuthenticate(body string) []SipHeader {
    return []SipHeader{ createSipWWWAuthenticateObj(body) }
}

func NewSipWWWAuthenticateWithRealm(realm string) *SipWWWAuthenticate {
    return &SipWWWAuthenticate{
        normalName  : _sip_www_authenticate_name,
        body        : newSipWWWAutenticateBody(realm),
    }
}

func newSipWWWAutenticateBody(realm string) *SipWWWAuthenticateBody {
    buf := make([]byte, 20)
    rand.Read(buf)
    return &SipWWWAuthenticateBody{
        realm : sippy_net.NewMyAddress(realm),
        nonce : fmt.Sprintf("%x", buf),
    }
}

func createSipWWWAuthenticateObj(body string) *SipWWWAuthenticate {
    return &SipWWWAuthenticate{
        string_body     : body,
    }
}

func (self *SipWWWAuthenticate) parse() error {
    tmp := sippy_utils.FieldsN(self.string_body, 2)
    if len(tmp) != 2 {
        return errors.New("Error parsing authentication (1)")
    }
    body := &SipWWWAuthenticateBody{}
    for _, part := range strings.Split(tmp[1], ",") {
        arr := strings.SplitN(strings.TrimSpace(part), "=", 2)
        if len(arr) != 2 { continue }
        switch arr[0] {
        case "realm":
            body.realm = sippy_net.NewMyAddress(strings.Trim(arr[1], "\""))
        case "nonce":
            body.nonce = strings.Trim(arr[1], "\"")
        }
    }
    self.body = body
    return nil
}

func (self SipWWWAuthenticate) GetBody() (*SipWWWAuthenticateBody, error) {
    if self.body == nil {
        if err := self.parse(); err != nil {
            return nil, err
        }
    }
    return self.body, nil
}

func (self *SipWWWAuthenticate) StringBody() string {
    return self.LocalStringBody(nil)
}

func (self *SipWWWAuthenticate) String() string {
    return self.LocalStr(nil, false)
}

func (self *SipWWWAuthenticate) LocalStr(hostport *sippy_net.HostPort, compact bool) string {
    return self.Name() + ": " + self.LocalStringBody(hostport)
}

func (self *SipWWWAuthenticate) LocalStringBody(hostport *sippy_net.HostPort) string {
    if self.body != nil {
        return self.body.localString(hostport)
    }
    return self.string_body
}

func (self *SipWWWAuthenticateBody) localString(hostport *sippy_net.HostPort) string {
    if hostport != nil && self.realm.IsSystemDefault() {
        return "Digest realm=\"" + hostport.Host.String() + "\",nonce=\"" + self.nonce + "\""
    }
    return "Digest realm=\"" + self.realm.String() + "\",nonce=\"" + self.nonce + "\""
}

func (self *SipWWWAuthenticateBody) GetRealm() string {
    return self.realm.String()
}

func (self *SipWWWAuthenticateBody) GetNonce() string {
    return self.nonce
}

func (self *SipWWWAuthenticate) GetCopy() *SipWWWAuthenticate {
    tmp := *self
    if self.body != nil {
        self.body = self.body.getCopy()
    }
    return &tmp
}

func (self *SipWWWAuthenticateBody) getCopy() *SipWWWAuthenticateBody {
    tmp := *self
    return &tmp
}

func (self *SipWWWAuthenticate) GetCopyAsIface() SipHeader {
    return self.GetCopy()
}
<commit_msg>Do not forget to initialize the normalName base class.<commit_after>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy_header

import (
    "crypto/rand"
    "errors"
    "fmt"
    "strings"

    "sippy/net"
    "sippy/utils"
)

type SipWWWAuthenticateBody struct {
    realm *sippy_net.MyAddress
    nonce string
}

type SipWWWAuthenticate struct {
    normalName
    string_body     string
    body            *SipWWWAuthenticateBody
}

var _sip_www_authenticate_name normalName = newNormalName("WWW-Authenticate")

func CreateSipWWWAuthenticate(body string) []SipHeader {
    return []SipHeader{ createSipWWWAuthenticateObj(body) }
}

func NewSipWWWAuthenticateWithRealm(realm string) *SipWWWAuthenticate {
    return &SipWWWAuthenticate{
        normalName  : _sip_www_authenticate_name,
        body        : newSipWWWAutenticateBody(realm),
    }
}

func newSipWWWAutenticateBody(realm string) *SipWWWAuthenticateBody {
    buf := make([]byte, 20)
    rand.Read(buf)
    return &SipWWWAuthenticateBody{
        realm : sippy_net.NewMyAddress(realm),
        nonce : fmt.Sprintf("%x", buf),
    }
}

func createSipWWWAuthenticateObj(body string) *SipWWWAuthenticate {
    return &SipWWWAuthenticate{
        normalName      : _sip_www_authenticate_name,
        string_body     : body,
    }
}

func (self *SipWWWAuthenticate) parse() error {
    tmp := sippy_utils.FieldsN(self.string_body, 2)
    if len(tmp) != 2 {
        return errors.New("Error parsing authentication (1)")
    }
    body := &SipWWWAuthenticateBody{}
    for _, part := range strings.Split(tmp[1], ",") {
        arr := strings.SplitN(strings.TrimSpace(part), "=", 2)
        if len(arr) != 2 { continue }
        switch arr[0] {
        case "realm":
            body.realm = sippy_net.NewMyAddress(strings.Trim(arr[1], "\""))
        case "nonce":
            body.nonce = strings.Trim(arr[1], "\"")
        }
    }
    self.body = body
    return nil
}

func (self SipWWWAuthenticate) GetBody() (*SipWWWAuthenticateBody, error) {
    if self.body == nil {
        if err := self.parse(); err != nil {
            return nil, err
        }
    }
    return self.body, nil
}

func (self *SipWWWAuthenticate) StringBody() string {
    return self.LocalStringBody(nil)
}

func (self *SipWWWAuthenticate) String() string {
    return self.LocalStr(nil, false)
}

func (self *SipWWWAuthenticate) LocalStr(hostport *sippy_net.HostPort, compact bool) string {
    return self.Name() + ": " + self.LocalStringBody(hostport)
}

func (self *SipWWWAuthenticate) LocalStringBody(hostport *sippy_net.HostPort) string {
    if self.body != nil {
        return self.body.localString(hostport)
    }
    return self.string_body
}

func (self *SipWWWAuthenticateBody) localString(hostport *sippy_net.HostPort) string {
    if hostport != nil && self.realm.IsSystemDefault() {
        return "Digest realm=\"" + hostport.Host.String() + "\",nonce=\"" + self.nonce + "\""
    }
    return "Digest realm=\"" + self.realm.String() + "\",nonce=\"" + self.nonce + "\""
}

func (self *SipWWWAuthenticateBody) GetRealm() string {
    return self.realm.String()
}

func (self *SipWWWAuthenticateBody) GetNonce() string {
    return self.nonce
}

func (self *SipWWWAuthenticate) GetCopy() *SipWWWAuthenticate {
    tmp := *self
    if self.body != nil {
        self.body = self.body.getCopy()
    }
    return &tmp
}

func (self *SipWWWAuthenticateBody) getCopy() *SipWWWAuthenticateBody {
    tmp := *self
    return &tmp
}

func (self *SipWWWAuthenticate) GetCopyAsIface() SipHeader {
    return self.GetCopy()
}
<|endoftext|>


<commit_before>package scheduler

import (
	"fmt"
	"github.com/dedis/cothority/network"
	"github.com/dedis/crypto/abstract"
	cryptoconfig "github.com/dedis/crypto/config"
	"github.com/dedis/crypto/random"
	"github.com/lbarman/prifi/prifi-lib"
	"github.com/lbarman/prifi/prifi-lib/config"
	"strconv"
	"testing"
)

type PrivatePublicPair struct {
	Private abstract.Scalar
	Public  abstract.Point
}

/*
 * Client 1 computes : p1 * B = P1
 * Client 2 computes : p2 * B = P2
 * Relay picks a base B
 * Relay sends P1, P2, B to trustee
 * Trustee 1 pick c1
 * Trustee 1 compute B1 = B * c1
 * Trustee 1 compute P1' = P1 * c1 = p1 * c1 * B
 * Trustee 1 compute P2' = P2 * c1 = p2 * c1 * B
 * Relay collect, then sends P1', P2', B1
 * Trustee 2 pick c2
 * Trustee 2 compute B2 = B1 * c2 = B * c1 * c2
 * Trustee 2 compute P1'' = P1' * c2 = p1 * c1 * c2 * B
 * Trustee 2 compute P2'' = P2' * c2 = p2 * c1 * c2 * B
 * Relay sends P1'', P2'', s2 to clients
 * Client 1 compute p1 * s2 * B = p1 * s0 * c1 * c2 * B = P1''
 * Client 2 compute p2 * s2 * B = p2 * s0 * c1 * c2 * B = P2''
 */
func TestWholeNeffShuffle(t *testing.T) {

	nTrustees := 2
	nClients := 2

	clients := make([]*PrivatePublicPair, nClients)
	for i := 0; i < nClients; i++ {
		pub, priv := genKeyPair()
		clients[i] = new(PrivatePublicPair)
		clients[i].Public = pub
		clients[i].Private = priv
	}

	//create the scheduler
	n := new(neffShuffleScheduler) //this will hold 1 relay, 1 trustee at most. Recreate n for >1 trustee
	n.init()

	//init the trustees
	trustees := make([]*neffShuffleScheduler, nTrustees)
	for i := 0; i < nTrustees; i++ {
		trustees[i] = new(neffShuffleScheduler)
		trustees[i].init()
		trustee := cryptoconfig.NewKeyPair(network.Suite)
		trustees[i].TrusteeView.init(i, trustee.Secret, trustee.Public)
	}

	//init the relay
	n.RelayView.init(nTrustees)
	for i := 0; i < nClients; i++ {
		n.RelayView.AddClient(clients[i].Public)
	}

	isDone := false
	i := 0
	for !isDone {
		if i >= nTrustees {
			t.Error("Should only shuffle" + strconv.Itoa(nTrustees) + ", but we did one more loop")
		}

		//the relay send the shuffle send it to the next trustee
		toSend, err := n.RelayView.SendToNextTrustee()
		if err != nil {
			t.Error(err)
		}
		parsed := toSend.(*prifi_lib.REL_TRU_TELL_CLIENTS_PKS_AND_EPH_PKS_AND_BASE)

		//who receives it
		shuffleKeyPos := false //so we can test easily
		toSend2, err := trustees[i].TrusteeView.ReceivedShuffleFromRelay(parsed.Base, parsed.Pks, shuffleKeyPos)
		if err != nil {
			t.Error(err)
		}
		parsed2 := toSend2.(*prifi_lib.TRU_REL_TELL_NEW_BASE_AND_EPH_PKS)

		// TEST: Trustee i compute B[i] = B[i-1] * c[i]
		B_i_minus_1 := n.RelayView.InitialBase
		if i > 0 {
			B_i_minus_1 = n.RelayView.Bases[i-1]
		}
		c_i := trustees[i].TrusteeView.SecretCoeff
		B_i := config.CryptoSuite.Point().Mul(B_i_minus_1, c_i)

		if !parsed2.NewBase.Equal(B_i) {
			t.Error("B[" + strconv.Itoa(i+1) + "] is computed incorrectly")
		}

		// TEST: Trustee i compute P1'[i] = P1'[i-1] * c[i] = p1 * c[1] ... c[i] * B
		p1 := clients[0].Private
		c_s := config.CryptoSuite.Scalar().One()
		for j := 0; j <= i; j++ {
			c_j := trustees[j].TrusteeView.SecretCoeff
			c_s = config.CryptoSuite.Scalar().Mul(c_s, c_j)
		}
		B := config.CryptoSuite.Point().Base()
		p1_c_s := config.CryptoSuite.Scalar().Mul(p1, c_s)
		LHS := config.CryptoSuite.Point().Mul(B, p1_c_s)

		if !parsed2.NewEphPks[0].Equal(LHS) {
			t.Error("P1'[" + strconv.Itoa(i+1) + "] is computed incorrectly")
		}

		// TEST: Trustee i compute P2'[i] = P2'[i-1] * c[i] = p2 * c[1] ... c[i] * B
		p2 := clients[1].Private
		p2_c_s := config.CryptoSuite.Scalar().Mul(p2, c_s)
		LHS = config.CryptoSuite.Point().Mul(B, p2_c_s)

		if !parsed2.NewEphPks[1].Equal(LHS) {
			t.Error("P2'[" + strconv.Itoa(i+1) + "] is computed incorrectly")
		}

		//Specialized test for trustee n°1 (0-th trustee)
		if i == 0 {
			// Trustee 1 compute B1 = B * c1
			B := n.RelayView.InitialBase
			c1 := trustees[0].TrusteeView.SecretCoeff
			if !parsed2.NewBase.Equal(config.CryptoSuite.Point().Mul(B, c1)) {
				t.Error("B1 is computed incorrectly")
			}

			// Trustee 1 compute P1' = P1 * c1 = p1 * c1 * B
			p1prime := config.CryptoSuite.Scalar().Mul(clients[0].Private, c1)
			if !parsed2.NewEphPks[0].Equal(config.CryptoSuite.Point().Mul(B, p1prime)) {
				t.Error("P1' is computed incorrectly")
			}

			// Trustee 1 compute P2' = P2 * c1 = p2 * c1 * B
			p2prime := config.CryptoSuite.Scalar().Mul(clients[1].Private, c1)
			if !parsed2.NewEphPks[1].Equal(config.CryptoSuite.Point().Mul(B, p2prime)) {
				t.Error("P2' is computed incorrectly")
			}
		}

		//Specialized test for trustee n°2 (1st trustee)
		if i == 1 {

			//* Trustee 2 compute B2 = B1 * c2 = B * c1 * c2
			B := n.RelayView.InitialBase
			c1 := trustees[0].TrusteeView.SecretCoeff
			c2 := trustees[1].TrusteeView.SecretCoeff
			c1c2 := config.CryptoSuite.Scalar().Mul(c1, c2)
			if !parsed2.NewBase.Equal(config.CryptoSuite.Point().Mul(B, c1c2)) {
				t.Error("B2 is computed incorrectly (2)")
			}

			//* Trustee 2 compute P1'' = P1' * c2 = p1 * c1 * c2 * B
			p1prime2 := config.CryptoSuite.Scalar().Mul(clients[0].Private, c1c2)
			if !parsed2.NewEphPks[0].Equal(config.CryptoSuite.Point().Mul(B, p1prime2)) {
				t.Error("P1'' is computed incorrectly")
			}
			//* Trustee 2 compute P2'' = P2' * c2 = p2 * c1 * c2 * B
			p2prime2 := config.CryptoSuite.Scalar().Mul(clients[1].Private, c1c2)
			if !parsed2.NewEphPks[1].Equal(config.CryptoSuite.Point().Mul(B, p2prime2)) {
				t.Error("P2'' is computed incorrectly")
			}
		}

		//and answers, the relay receives it
		isDone, err = n.RelayView.ReceivedShuffleFromTrustee(parsed2.NewBase, parsed2.NewEphPks, parsed2.Proof)

		i++
	}

	toSend3, err := n.RelayView.SendTranscript()
	if err != nil {
		t.Error(err)
	}
	parsed3 := toSend3.(*prifi_lib.REL_TRU_TELL_TRANSCRIPT)

	for j := 0; j < nTrustees; j++ {
		toSend4, err := trustees[j].TrusteeView.ReceivedTranscriptFromRelay(parsed3.Bases, parsed3.EphPks, parsed3.Proofs)
		if err != nil {
			t.Error(err)
		}
		parsed4 := toSend4.(*prifi_lib.TRU_REL_SHUFFLE_SIG)

		done, err := n.RelayView.ReceivedSignatureFromTrustee(parsed4.TrusteeID, parsed4.Sig)

		if done && j != nTrustees-1 {
			t.Error("Relay collecting signature, but is done too early, only received " + strconv.Itoa(j+1) + " signatures out of " + strconv.Itoa(nTrustees))
		}
		if !done && j == nTrustees-1 {
			t.Error("Relay collecting signature, but is not done, yet we have all signatures")
		}
	}

	trusteesPks := make([]abstract.Point, nTrustees)
	for j := 0; j < nTrustees; j++ {
		trusteesPks[j] = trustees[j].TrusteeView.PublicKey
	}

	toSend5, err := n.RelayView.VerifySigsAndSendToClients(trusteesPks)
	if err != nil {
		t.Error(err)
	}
	parsed5 := toSend5.(*prifi_lib.REL_CLI_TELL_EPH_PKS_AND_TRUSTEES_SIG)

	//client verify the sig and recognize their slot
	for j := 0; j < nClients; j++ {
		mySlot, err := n.ClientVerifySigAndRecognizeSlot(clients[j].Private, trusteesPks, parsed5.Base, parsed5.EphPks, parsed5.TrusteesSigs)
		if err != nil {
			t.Error(err)
		}
		fmt.Println("Client", j, "got assigned slot", mySlot)
	}

}

func genKeyPair() (abstract.Point, abstract.Scalar) {

	base := config.CryptoSuite.Point().Base()
	priv := config.CryptoSuite.Scalar().Pick(random.Stream)
	pub := config.CryptoSuite.Point().Mul(base, priv)

	return pub, priv
}
<commit_msg>New scheduler ready and tested<commit_after>package scheduler

import (
	"fmt"
	"github.com/dedis/cothority/network"
	"github.com/dedis/crypto/abstract"
	cryptoconfig "github.com/dedis/crypto/config"
	"github.com/dedis/crypto/random"
	"github.com/lbarman/prifi/prifi-lib"
	"github.com/lbarman/prifi/prifi-lib/config"
	"strconv"
	"testing"
)

type PrivatePublicPair struct {
	Private abstract.Scalar
	Public  abstract.Point
}

/*
 * Client 1 computes : p1 * B = P1
 * Client 2 computes : p2 * B = P2
 * Relay picks a base B
 * Relay sends P1, P2, B to trustee
 * Trustee 1 pick c1
 * Trustee 1 compute B1 = B * c1
 * Trustee 1 compute P1' = P1 * c1 = p1 * c1 * B
 * Trustee 1 compute P2' = P2 * c1 = p2 * c1 * B
 * Relay collect, then sends P1', P2', B1
 * Trustee 2 pick c2
 * Trustee 2 compute B2 = B1 * c2 = B * c1 * c2
 * Trustee 2 compute P1'' = P1' * c2 = p1 * c1 * c2 * B
 * Trustee 2 compute P2'' = P2' * c2 = p2 * c1 * c2 * B
 * Relay sends P1'', P2'', s2 to clients
 * Client 1 compute p1 * s2 * B = p1 * s0 * c1 * c2 * B = P1''
 * Client 2 compute p2 * s2 * B = p2 * s0 * c1 * c2 * B = P2''
 */
func TestWholeNeffShuffle(t *testing.T) {

	nClientsRange := []int{1, 2, 3, 4, 5, 10, 100}
	nTrusteeRange := []int{1, 2, 3, 5, 10}

	//standard testing. shuffleKeyPos=false to allow testing
	for _, nClients := range nClientsRange {
		for _, nTrustees := range nTrusteeRange {
			//standard testing
			fmt.Println("Testing for", nClients, "clients,", nTrustees, "trustees...")
			NeffShuffleTestHelper(t, nClients, nTrustees, false)
		}
	}

	//output distribution testing.
	nClientsRange = []int{2, 3, 4, 5, 10}
	nTrusteeRange = []int{1}

	repetition := 100
	for _, nClients := range nClientsRange {
		for _, nTrustees := range nTrusteeRange {
			mappingDistrib := make([][]float64, nClients)
			for k := 0; k < nClients; k++ {
				mappingDistrib[k] = make([]float64, nClients)
			}
			fmt.Print("Testing distribution for ", nClients, " clients, ", nTrustees, " trustees... ")
			for i := 0; i < repetition; i++ {
				mapping := NeffShuffleTestHelper(t, nClients, nTrustees, true)
				for clientID, slot := range mapping {
					mappingDistrib[clientID][slot] += float64(1)
				}
			}
			maxDeviation := float64(-1)
			for clientID, _ := range mappingDistrib {
				for slot := 0; slot < nClients; slot++ {
					//compute deviation
					expectedValue := float64(100) / float64(len(mappingDistrib[clientID]))
					mappingDistrib[clientID][slot] -= expectedValue
					if mappingDistrib[clientID][slot] < 0 {
						mappingDistrib[clientID][slot] = -mappingDistrib[clientID][slot]
					}

					//store max deviation
					if mappingDistrib[clientID][slot] > maxDeviation {
						maxDeviation = mappingDistrib[clientID][slot]
					}
				}
			}
			fmt.Printf("+-%d%%\n", int(maxDeviation))
			if int(maxDeviation) > 30 {
				t.Error(errors.New("Max allowed distribution biais is 30%"))
			}
		}
	}
}

func NeffShuffleTestHelper(t *testing.T, nClients int, nTrustees int, shuffleKeyPos bool) []int {
	clients := make([]*PrivatePublicPair, nClients)
	for i := 0; i < nClients; i++ {
		pub, priv := genKeyPair()
		clients[i] = new(PrivatePublicPair)
		clients[i].Public = pub
		clients[i].Private = priv
	}

	//create the scheduler
	n := new(neffShuffleScheduler) //this will hold 1 relay, 1 trustee at most. Recreate n for >1 trustee
	n.init()

	//init the trustees
	trustees := make([]*neffShuffleScheduler, nTrustees)
	for i := 0; i < nTrustees; i++ {
		trustees[i] = new(neffShuffleScheduler)
		trustees[i].init()
		trustee := cryptoconfig.NewKeyPair(network.Suite)
		trustees[i].TrusteeView.init(i, trustee.Secret, trustee.Public)
	}

	//init the relay
	err := n.RelayView.init(nTrustees)
	if err != nil {
		t.Error(err)
	}
	for i := 0; i < nClients; i++ {
		n.RelayView.AddClient(clients[i].Public)
	}

	isDone := false
	i := 0
	for !isDone {
		if i >= nTrustees {
			t.Error("Should only shuffle" + strconv.Itoa(nTrustees) + ", but we did one more loop")
		}

		//the relay send the shuffle send it to the next trustee
		toSend, err := n.RelayView.SendToNextTrustee()
		if err != nil {
			t.Error(err)
		}
		parsed := toSend.(*prifi_lib.REL_TRU_TELL_CLIENTS_PKS_AND_EPH_PKS_AND_BASE)

		//who receives it
		toSend2, err := trustees[i].TrusteeView.ReceivedShuffleFromRelay(parsed.Base, parsed.Pks, shuffleKeyPos)
		if err != nil {
			t.Error(err)
		}
		parsed2 := toSend2.(*prifi_lib.TRU_REL_TELL_NEW_BASE_AND_EPH_PKS)

		// TEST: Trustee i compute B[i] = B[i-1] * c[i]
		B_i_minus_1 := n.RelayView.InitialBase
		if i > 0 {
			B_i_minus_1 = n.RelayView.Bases[i-1]
		}
		c_i := trustees[i].TrusteeView.SecretCoeff
		B_i := config.CryptoSuite.Point().Mul(B_i_minus_1, c_i)

		if !parsed2.NewBase.Equal(B_i) {
			t.Error("B[" + strconv.Itoa(i+1) + "] is computed incorrectly")
		}

		//if shuffle the key pos, we cannot test this easily
		if !shuffleKeyPos {
			// TEST: Trustee i compute P1'[i] = P1'[i-1] * c[i] = p1 * c[1] ... c[i] * B

			for clientID := 0; clientID < nClients; clientID++ {
				p1 := clients[clientID].Private
				c_s := config.CryptoSuite.Scalar().One()
				for j := 0; j <= i; j++ {
					c_j := trustees[j].TrusteeView.SecretCoeff
					c_s = config.CryptoSuite.Scalar().Mul(c_s, c_j)
				}
				B := config.CryptoSuite.Point().Base()
				p1_c_s := config.CryptoSuite.Scalar().Mul(p1, c_s)
				LHS := config.CryptoSuite.Point().Mul(B, p1_c_s)

				if !parsed2.NewEphPks[clientID].Equal(LHS) {
					t.Error("P" + strconv.Itoa(clientID) + "'[" + strconv.Itoa(i+1) + "] is computed incorrectly")
				}
			}

			//Specialized test for trustee n°1 (0-th trustee)
			if i == 0 {
				// Trustee 1 compute B1 = B * c1
				B := n.RelayView.InitialBase
				c1 := trustees[0].TrusteeView.SecretCoeff
				if !parsed2.NewBase.Equal(config.CryptoSuite.Point().Mul(B, c1)) {
					t.Error("B1 is computed incorrectly")
				}

				// Trustee 1 compute P1' = P1 * c1 = p1 * c1 * B
				for clientID := 0; clientID < nClients; clientID++ {
					p1prime := config.CryptoSuite.Scalar().Mul(clients[clientID].Private, c1)
					if !parsed2.NewEphPks[clientID].Equal(config.CryptoSuite.Point().Mul(B, p1prime)) {
						t.Error("P" + strconv.Itoa(clientID) + "' is computed incorrectly")
					}
				}
			}

			//Specialized test for trustee n°2 (1st trustee)
			if i == 1 {

				//* Trustee 2 compute B2 = B1 * c2 = B * c1 * c2
				B := n.RelayView.InitialBase
				c1 := trustees[0].TrusteeView.SecretCoeff
				c2 := trustees[1].TrusteeView.SecretCoeff
				c1c2 := config.CryptoSuite.Scalar().Mul(c1, c2)
				if !parsed2.NewBase.Equal(config.CryptoSuite.Point().Mul(B, c1c2)) {
					t.Error("B2 is computed incorrectly (2)")
				}

				//* Trustee 2 compute P1'' = P1' * c2 = p1 * c1 * c2 * B
				for clientID := 0; clientID < nClients; clientID++ {
					p1prime2 := config.CryptoSuite.Scalar().Mul(clients[clientID].Private, c1c2)
					if !parsed2.NewEphPks[clientID].Equal(config.CryptoSuite.Point().Mul(B, p1prime2)) {
						t.Error("P" + strconv.Itoa(clientID) + "'' is computed incorrectly")
					}
				}
			}
		}

		//and answers, the relay receives it
		isDone, err = n.RelayView.ReceivedShuffleFromTrustee(parsed2.NewBase, parsed2.NewEphPks, parsed2.Proof)

		i++
	}

	toSend3, err := n.RelayView.SendTranscript()
	if err != nil {
		t.Error(err)
	}
	parsed3 := toSend3.(*prifi_lib.REL_TRU_TELL_TRANSCRIPT)

	for j := 0; j < nTrustees; j++ {
		toSend4, err := trustees[j].TrusteeView.ReceivedTranscriptFromRelay(parsed3.Bases, parsed3.EphPks, parsed3.Proofs)
		if err != nil {
			t.Error(err)
		}
		parsed4 := toSend4.(*prifi_lib.TRU_REL_SHUFFLE_SIG)

		done, err := n.RelayView.ReceivedSignatureFromTrustee(parsed4.TrusteeID, parsed4.Sig)

		if done && j != nTrustees-1 {
			t.Error("Relay collecting signature, but is done too early, only received " + strconv.Itoa(j+1) + " signatures out of " + strconv.Itoa(nTrustees))
		}
		if !done && j == nTrustees-1 {
			t.Error("Relay collecting signature, but is not done, yet we have all signatures")
		}
	}

	trusteesPks := make([]abstract.Point, nTrustees)
	for j := 0; j < nTrustees; j++ {
		trusteesPks[j] = trustees[j].TrusteeView.PublicKey
	}

	toSend5, err := n.RelayView.VerifySigsAndSendToClients(trusteesPks)
	if err != nil {
		t.Error(err)
	}
	parsed5 := toSend5.(*prifi_lib.REL_CLI_TELL_EPH_PKS_AND_TRUSTEES_SIG)

	mapping := make([]int, nClients)

	//client verify the sig and recognize their slot
	for j := 0; j < nClients; j++ {
		mySlot, err := n.ClientVerifySigAndRecognizeSlot(clients[j].Private, trusteesPks, parsed5.Base, parsed5.EphPks, parsed5.TrusteesSigs)
		if err != nil {
			t.Error(err)
		}
		mapping[j] = mySlot
	}

	//test that mapping is valid
	for j := 0; j < nClients; j++ {

		if mapping[j] < 0 || mapping[j] >= nClients {
			t.Error("Final mapping invalid,", j, "->", mapping[j])
		}

		//test for duplicate
		mySlot := mapping[j]
		for k := 0; k < nClients; k++ {
			if k != j {
				if mapping[k] == mySlot {
					t.Error("Collision, mapping[", j, "]=mapping[", k, "]=", mySlot)
				}
			}
		}
	}

	return mapping
}

func genKeyPair() (abstract.Point, abstract.Scalar) {

	base := config.CryptoSuite.Point().Base()
	priv := config.CryptoSuite.Scalar().Pick(random.Stream)
	pub := config.CryptoSuite.Point().Mul(base, priv)

	return pub, priv
}
<|endoftext|>


<commit_before>package main

import (
	"aguin/config"
	"aguin/crypto"
	"aguin/model"
	"flag"
	"fmt"
)

func main() {
	var (
		configPath string
		email      string
		name       string
		app        string
	)
	flag.StringVar(&email, "e", "", "Your email")
	flag.StringVar(&name, "n", "", "Your name")
	flag.StringVar(&app, "a", "", "Your application name")
	flag.StringVar(&configPath, "c", "", "Path to configurations")

	flag.Parse()
	if email == "" || name == "" || app == "" {
		fmt.Println("You need to specify your email, your name and your application name")
		flag.Usage()
		return
	}
	if configPath != "" {
		config.SetConfigPath(configPath)
	}
	config.ReadConfig()

	session := model.Session()
	model.EnsureIndex(false)
	u := model.User{}
	u.Email = email
	u.Name = name
	u.Save(session)
	ucollection := model.UserCollection(session)
	ucollection.Find(map[string]interface{}{"email": email}).One(&u)
	fmt.Printf("email: %s, name: %s\n", u.Email, u.Name)
	a := model.Application{}
	a.UserId = u.Id
	a.Name = app
	a.Secret = crypto.RandomHex(16)
	a.Save(session)
	acollection := model.AppCollection(session)
	acollection.Find(map[string]interface{}{"userid": u.Id, "name": app}).One(&a)
	fmt.Printf("app_name: %s, api_key: %s, api_secret: %s, aes_key: %s\n", a.Name, a.Id.Hex(), a.Secret, a.Secret)
}
<commit_msg>Using bson and bson tag<commit_after>package main

import (
	"aguin/config"
	"aguin/crypto"
	"aguin/model"
	"aguin/utils"
	"flag"
	"fmt"
	"gopkg.in/mgo.v2/bson"
)

func main() {
	var (
		configPath string
		email      string
		name       string
		app        string
	)
	flag.StringVar(&email, "e", "", "Your email")
	flag.StringVar(&name, "n", "", "Your name")
	flag.StringVar(&app, "a", "", "Your application name")
	flag.StringVar(&configPath, "c", "", "Path to configurations")

	flag.Parse()
	if email == "" || name == "" || app == "" {
		fmt.Println("You need to specify your email, your name and your application name")
		flag.Usage()
		return
	}
	if configPath != "" {
		config.SetConfigPath(configPath)
	}
	config.ReadConfig()

	session := model.Session()
	model.EnsureIndex(false)
	u := model.User{}
	u.Email = email
	u.Name = name
	u.Save(session)
	ucollection := model.UserCollection(session)
	user_tags := utils.GetFieldsTag(&model.User{}, "bson")
	ucollection.Find(bson.M{user_tags.Get("Email"): email}).One(&u)
	fmt.Printf("email: %s, name: %s\n", u.Email, u.Name)
	a := model.Application{}
	a.UserId = u.Id
	a.Name = app
	a.Secret = crypto.RandomHex(16)
	a.Save(session)
	acollection := model.AppCollection(session)
	app_tags := utils.GetFieldsTag(&model.Application{}, "bson")
	acollection.Find(bson.M{app_tags.Get("UserId"): u.Id, app_tags.Get("Name"): app}).One(&a)
	fmt.Printf("app_name: %s, api_key: %s, api_secret: %s, aes_key: %s\n", a.Name, a.Id.Hex(), a.Secret, a.Secret)
}
<|endoftext|>


<commit_before>// Copyright

package models

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"time"
)

// types for the bookmarks database
type (

	// Bookmarks stores a list of bookmarks.
	// The Key which is generated when the object is passed to the collection.
	// The Created and Viewed fields are maintained by the collection.
	// The user of the package should initialise the List field.
	Bookmarks struct {
		//  Id		bson.ObjectId 	`json:"id"	bson:"_id"`
		Key     string     "key"
		Created time.Time  "created"
		Viewed  time.Time  "viewed"
		List    []Bookmark "list"
	}

	// Bookmark stores a single bookmark.
	// The user of the package should initialise the URL and Description fields.
	Bookmark struct {
		//  Id	bson.ObjectId 	`json:"id"	bson:"_id"`
		URL         string "url"
		Description string "description"
	}

	// bookmarkRepo stores the collection
	bookmarkRepo struct {
		Collection *mgo.Collection
	}

	// AddRequest stores a request for adding a Bookmarks object
	// to the bookmarks collection
	AddRequest struct {
		List  Bookmarks
		Reply chan string // Return the key
	}

	// ListRetrieve stores a request for retrieving a Bookmarks object
	// from the bookmarks collection by key
	ListRetrieve struct {
		Key   string
		Reply chan Bookmarks // Returns the Bookmarks object found
	}
)

// Database Collection info
const listCollection = "lists"

// Retrieve finds a Bookmarks object in the database
// with the value of the Key field given by key
func retrieve(lists bookmarkRepo, key string) Bookmarks {

	result := Bookmarks{}

    change := mgo.Change{
          Update: bson.M{"$set": bson.M{"viewed": time.Now()}},
          ReturnNew: true,
    }
  	_, err := lists.Collection.Find(bson.M{"key": key}).Apply(change, &result)

//	err := lists.Collection.Find(bson.M{"key": key}).One(&result)
	fmt.Println(result)
	if err != mgo.ErrNotFound {
		if err != nil {
			panic(err)
		}
	}

	return result

}

// save inserts a Bookmarks object into the database
func save(lists bookmarkRepo, bookmarks Bookmarks) {

	// Store the current time
	created := time.Now()
	bookmarks.Created = created
	bookmarks.Viewed = created

	// Enter the bookmarks document into the database
	err := lists.Collection.Insert(bookmarks)
	if err != nil {
		panic(err)
	}

}

// BookmarksCollection maintains the bookmarks collection
// and serves requests. It provides channels for retrieval,
// insertion, and removal. It communicates to WordList via
// the code channel.
func BookmarksCollection(getList chan ListRetrieve,
	addList chan AddRequest,
	removeList chan string) {
	// Run database
	newColRequest := make(chan ColRequest)
	dbQuit := make(chan bool)
	go Database(newColRequest, dbQuit)
	defer close(newColRequest)
	defer close(dbQuit)

	// Run the code generator - opens the words collection
	newCode := make(chan string)  // For getting a new unique code
	freeCode := make(chan string) // For freeing a code after deletion
	go UniqueCodeTracker(newCode, freeCode, newColRequest)
	defer close(newCode)
	defer close(freeCode)

	// Get the bookmarks collection from the database
	reply := make(chan *mgo.Collection)
	newColRequest <- ColRequest{listCollection, reply}
	collection := <-reply
	lists := bookmarkRepo{collection}

	// Serve requests
	// 1. Get list by key
	// 2. Add list
	// 3. Remove list (propagate entries to parents)
	for {
		select {
		case req, ok := <-getList: // Retrieve list by key
			if ok {
				req.Reply <- retrieve(lists, req.Key) // reply by req.key
			} else { // Caller is dead
				return // end silently
			}
		case req, ok := <-addList:
			if ok {
				req.List.Key = <-newCode  // Generate key
				save(lists, req.List)     // Enter list into database
				req.Reply <- req.List.Key // Return key
			} else { // Caller is dead
				return // end silently
			}
		case _, ok := <-removeList: // Remove list by key
			if ok {
				// To Delete list by key:
				// 1. Retrieve list
				// 2. Modify list dependencies
				// 3. Remove original from database
				// 4. Free key
				_ = 1
			} else { // Caller is dead
				return // end silently
			}
		}
	}

}
<commit_msg>Comments on new retrieve It works!<commit_after>// Copyright

package models

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"time"
)

// types for the bookmarks database
type (

	// Bookmarks stores a list of bookmarks.
	// The Key which is generated when the object is passed to the collection.
	// The Created and Viewed fields are maintained by the collection.
	// The user of the package should initialise the List field.
	Bookmarks struct {
		//  Id		bson.ObjectId 	`json:"id"	bson:"_id"`
		Key     string     "key"
		Created time.Time  "created"
		Viewed  time.Time  "viewed"
		List    []Bookmark "list"
	}

	// Bookmark stores a single bookmark.
	// The user of the package should initialise the URL and Description fields.
	Bookmark struct {
		//  Id	bson.ObjectId 	`json:"id"	bson:"_id"`
		URL         string "url"
		Description string "description"
	}

	// bookmarkRepo stores the collection
	bookmarkRepo struct {
		Collection *mgo.Collection
	}

	// AddRequest stores a request for adding a Bookmarks object
	// to the bookmarks collection
	AddRequest struct {
		List  Bookmarks
		Reply chan string // Return the key
	}

	// ListRetrieve stores a request for retrieving a Bookmarks object
	// from the bookmarks collection by key
	ListRetrieve struct {
		Key   string
		Reply chan Bookmarks // Returns the Bookmarks object found
	}
)

// Database Collection info
const listCollection = "lists"

// Retrieve finds a Bookmarks object in the database
// with the value of the Key field given by key
func retrieve(lists bookmarkRepo, key string) Bookmarks {

	result := Bookmarks{}

  	// Make change to touch object
    change := mgo.Change{
          Update: bson.M{"$set": bson.M{"viewed": time.Now()}},
          ReturnNew: true,
    }

  	// Get object (apply the change)
  	_, err := lists.Collection.Find(bson.M{"key": key}).Apply(change, &result)

  	// Don't worry if you didn't find anything
  	// result is still Bookmarks{} which is empty
  	if err != mgo.ErrNotFound {
		if err != nil {
			panic(err)
		}
	}

  	// Return the bookmarks object
	return result

}

// save inserts a Bookmarks object into the database
func save(lists bookmarkRepo, bookmarks Bookmarks) {

	// Store the current time
	created := time.Now()
	bookmarks.Created = created
	bookmarks.Viewed = created

	// Enter the bookmarks document into the database
	err := lists.Collection.Insert(bookmarks)
	if err != nil {
		panic(err)
	}

}

// BookmarksCollection maintains the bookmarks collection
// and serves requests. It provides channels for retrieval,
// insertion, and removal. It communicates to WordList via
// the code channel.
func BookmarksCollection(getList chan ListRetrieve,
	addList chan AddRequest,
	removeList chan string) {
	// Run database
	newColRequest := make(chan ColRequest)
	dbQuit := make(chan bool)
	go Database(newColRequest, dbQuit)
	defer close(newColRequest)
	defer close(dbQuit)

	// Run the code generator - opens the words collection
	newCode := make(chan string)  // For getting a new unique code
	freeCode := make(chan string) // For freeing a code after deletion
	go UniqueCodeTracker(newCode, freeCode, newColRequest)
	defer close(newCode)
	defer close(freeCode)

	// Get the bookmarks collection from the database
	reply := make(chan *mgo.Collection)
	newColRequest <- ColRequest{listCollection, reply}
	collection := <-reply
	lists := bookmarkRepo{collection}

	// Serve requests
	// 1. Get list by key
	// 2. Add list
	// 3. Remove list (propagate entries to parents)
	for {
		select {
		case req, ok := <-getList: // Retrieve list by key
			if ok {
				req.Reply <- retrieve(lists, req.Key) // reply by req.key
			} else { // Caller is dead
				return // end silently
			}
		case req, ok := <-addList:
			if ok {
				req.List.Key = <-newCode  // Generate key
				save(lists, req.List)     // Enter list into database
				req.Reply <- req.List.Key // Return key
			} else { // Caller is dead
				return // end silently
			}
		case _, ok := <-removeList: // Remove list by key
			if ok {
				// To Delete list by key:
				// 1. Retrieve list
				// 2. Modify list dependencies
				// 3. Remove original from database
				// 4. Free key
				_ = 1
			} else { // Caller is dead
				return // end silently
			}
		}
	}

}
<|endoftext|>


<commit_before>// Copyright

package models

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"time"
)

// types for the bookmarks database
type (

	// Bookmarks stores a list of bookmarks.
	// The Key which is generated when the object is passed to the collection.
	// The Created and Viewed fields are maintained by the collection.
	// The user of the package should initialise the List field.
	Bookmarks struct {
		//  Id		bson.ObjectId 	`json:"id"	bson:"_id"`
		Key     string     "key"
		Created time.Time  "created"
		Viewed  time.Time  "viewed"
		List    []Bookmark "list"
	}

	// Bookmark stores a single bookmark.
	// The user of the package should initialise the URL and Description fields.
	Bookmark struct {
		//  Id	bson.ObjectId 	`json:"id"	bson:"_id"`
		URL         string "url"
		Description string "description"
	}

	// bookmarkRepo stores the collection
	bookmarkRepo struct {
		Collection *mgo.Collection
	}

	// AddRequest stores a request for adding a Bookmarks object
	// to the bookmarks collection
	AddRequest struct {
		List  Bookmarks
		Reply chan string // Return the key
	}

	// ListRetrieve stores a request for retrieving a Bookmarks object
	// from the bookmarks collection by key
	ListRetrieve struct {
		Key   string
		Reply chan Bookmarks // Returns the Bookmarks object found
	}
)

// Database Collection info
const listCollection = "lists"

// Retrieve finds a Bookmarks object in the database
// with the value of the Key field given by key
func retrieve(lists bookmarkRepo, key string) Bookmarks {

	result := Bookmarks{}

  	// Make change to touch object
    change := mgo.Change{
          Update: bson.M{"$set": bson.M{"viewed": time.Now()}},
          ReturnNew: true,
    }

  	// Get object (apply the change)
  	_, err := lists.Collection.Find(bson.M{"key": key}).Apply(change, &result)

  	// Don't worry if you didn't find anything
  	// result is still Bookmarks{} which is empty
  	if err != mgo.ErrNotFound {
		if err != nil {
			panic(err)
		}
	}

  	// Return the bookmarks object
	return result

}

// save inserts a Bookmarks object into the database
func save(lists bookmarkRepo, bookmarks Bookmarks) {

	// Store the current time
	created := time.Now()
	bookmarks.Created = created
	bookmarks.Viewed = created

	// Enter the bookmarks document into the database
	err := lists.Collection.Insert(bookmarks)
	if err != nil {
		panic(err)
	}

}

// BookmarksCollection maintains the bookmarks collection
// and serves requests. It provides channels for retrieval,
// insertion, and removal. It communicates to WordList via
// the code channel.
func BookmarksCollection(getList chan ListRetrieve,
	addList chan AddRequest,
	removeList chan string) {
	// Run database
	newColRequest := make(chan ColRequest)
	dbQuit := make(chan bool)
	go Database(newColRequest, dbQuit)
	defer close(newColRequest)
	defer close(dbQuit)

	// Run the code generator - opens the words collection
	newCode := make(chan string)  // For getting a new unique code
	freeCode := make(chan string) // For freeing a code after deletion
	go UniqueCodeTracker(newCode, freeCode, newColRequest)
	defer close(newCode)
	defer close(freeCode)

	// Get the bookmarks collection from the database
	reply := make(chan *mgo.Collection)
	newColRequest <- ColRequest{listCollection, reply}
	collection := <-reply
	lists := bookmarkRepo{collection}

	// Serve requests
	// 1. Get list by key
	// 2. Add list
	// 3. Remove list (propagate entries to parents)
	for {
		select {
		case req, ok := <-getList: // Retrieve list by key
			if ok {
				req.Reply <- retrieve(lists, req.Key) // reply by req.key
			} else { // Caller is dead
				return // end silently
			}
		case req, ok := <-addList:
			if ok {
				req.List.Key = <-newCode  // Generate key
				save(lists, req.List)     // Enter list into database
				req.Reply <- req.List.Key // Return key
			} else { // Caller is dead
				return // end silently
			}
		case _, ok := <-removeList: // Remove list by key
			if ok {
				// To Delete list by key:
				// 1. Retrieve list
				// 2. Modify list dependencies
				// 3. Remove original from database
				// 4. Free key
				_ = 1
			} else { // Caller is dead
				return // end silently
			}
		}
	}

}
<commit_msg>gofmt'd code Only bookmarks.go changed<commit_after>// Copyright

package models

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"time"
)

// types for the bookmarks database
type (

	// Bookmarks stores a list of bookmarks.
	// The Key which is generated when the object is passed to the collection.
	// The Created and Viewed fields are maintained by the collection.
	// The user of the package should initialise the List field.
	Bookmarks struct {
		//  Id		bson.ObjectId 	`json:"id"	bson:"_id"`
		Key     string     "key"
		Created time.Time  "created"
		Viewed  time.Time  "viewed"
		List    []Bookmark "list"
	}

	// Bookmark stores a single bookmark.
	// The user of the package should initialise the URL and Description fields.
	Bookmark struct {
		//  Id	bson.ObjectId 	`json:"id"	bson:"_id"`
		URL         string "url"
		Description string "description"
	}

	// bookmarkRepo stores the collection
	bookmarkRepo struct {
		Collection *mgo.Collection
	}

	// AddRequest stores a request for adding a Bookmarks object
	// to the bookmarks collection
	AddRequest struct {
		List  Bookmarks
		Reply chan string // Return the key
	}

	// ListRetrieve stores a request for retrieving a Bookmarks object
	// from the bookmarks collection by key
	ListRetrieve struct {
		Key   string
		Reply chan Bookmarks // Returns the Bookmarks object found
	}
)

// Database Collection info
const listCollection = "lists"

// Retrieve finds a Bookmarks object in the database
// with the value of the Key field given by key
func retrieve(lists bookmarkRepo, key string) Bookmarks {

	result := Bookmarks{}

	// Make change to touch object
	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"viewed": time.Now()}},
		ReturnNew: true,
	}

	// Get object (apply the change)
	_, err := lists.Collection.Find(bson.M{"key": key}).Apply(change, &result)

	// Don't worry if you didn't find anything
	// result is still Bookmarks{} which is empty
	if err != mgo.ErrNotFound {
		if err != nil {
			panic(err)
		}
	}

	// Return the bookmarks object
	return result

}

// save inserts a Bookmarks object into the database
func save(lists bookmarkRepo, bookmarks Bookmarks) {

	// Store the current time
	created := time.Now()
	bookmarks.Created = created
	bookmarks.Viewed = created

	// Enter the bookmarks document into the database
	err := lists.Collection.Insert(bookmarks)
	if err != nil {
		panic(err)
	}

}

// BookmarksCollection maintains the bookmarks collection
// and serves requests. It provides channels for retrieval,
// insertion, and removal. It communicates to WordList via
// the code channel.
func BookmarksCollection(getList chan ListRetrieve,
	addList chan AddRequest,
	removeList chan string) {
	// Run database
	newColRequest := make(chan ColRequest)
	dbQuit := make(chan bool)
	go Database(newColRequest, dbQuit)
	defer close(newColRequest)
	defer close(dbQuit)

	// Run the code generator - opens the words collection
	newCode := make(chan string)  // For getting a new unique code
	freeCode := make(chan string) // For freeing a code after deletion
	go UniqueCodeTracker(newCode, freeCode, newColRequest)
	defer close(newCode)
	defer close(freeCode)

	// Get the bookmarks collection from the database
	reply := make(chan *mgo.Collection)
	newColRequest <- ColRequest{listCollection, reply}
	collection := <-reply
	lists := bookmarkRepo{collection}

	// Serve requests
	// 1. Get list by key
	// 2. Add list
	// 3. Remove list (propagate entries to parents)
	for {
		select {
		case req, ok := <-getList: // Retrieve list by key
			if ok {
				req.Reply <- retrieve(lists, req.Key) // reply by req.key
			} else { // Caller is dead
				return // end silently
			}
		case req, ok := <-addList:
			if ok {
				req.List.Key = <-newCode  // Generate key
				save(lists, req.List)     // Enter list into database
				req.Reply <- req.List.Key // Return key
			} else { // Caller is dead
				return // end silently
			}
		case _, ok := <-removeList: // Remove list by key
			if ok {
				// To Delete list by key:
				// 1. Retrieve list
				// 2. Modify list dependencies
				// 3. Remove original from database
				// 4. Free key
				_ = 1
			} else { // Caller is dead
				return // end silently
			}
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"
	"path"

	"labix.org/v2/mgo"

	"bitbucket.org/belak/go-seabird"
	"bitbucket.org/belak/irc"
	"bitbucket.org/belak/irc/mux"
)

type Config struct {
	Prefix string

	// Bot info
	Nick string
	User string
	Name string
	Pass string

	// Host
	Host        string
	TLS         bool
	TLSNoVerify bool

	// Cmds for on connect
	Cmds []string

	// Plugin config
	Plugins struct {
		Forecast string
	}
}

func init() {
	// Try HOME first then fall back to user.Current() because it needs cgo
	home := os.Getenv("HOME")
	if home == "" {
		user, err := user.Current()
		if err != nil {
			log.Fatalln(err)
		}
		home = user.HomeDir
	}

	flag.StringVar(&configFile, "F", path.Join(home, ".seabird", "main.json"), "alternate config file")
}

var configFile string

func loadConfig(filename string) *Config {
	file, err := os.Open(filename)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	config := &Config{}
	dec := json.NewDecoder(file)
	dec.Decode(config)

	return config
}

func main() {
	// Command line options
	flag.Parse()

	// Load the config file
	config := loadConfig(configFile)

	c := irc.NewClient(config.Nick, config.User, config.Name, config.Pass)

	// Connect to mongo
	sess, err := mgo.Dial("localhost")
	if err != nil {
		fmt.Println(err)
		return
	}

	db := sess.DB("seabird")

	// Add seabird
	cmds := mux.NewCommandMux(config.Prefix)
	ment := mux.NewMentionMux()

	// Coin Kick
	cmds.ChannelFunc("coin", seabird.CoinKickHandler)

	// URL stuff
	c.EventFunc("PRIVMSG", seabird.URLHandler)

	// Dice rolling
	ment.EventFunc(seabird.DiceHandler)

	// Add karma
	k := seabird.NewKarmaHandler(db.C("karma"))
	cmds.EventFunc("karma", k.Karma)
	c.EventFunc("PRIVMSG", k.Msg)

	// Add forecast
	f := seabird.NewForecastHandler(config.Plugins.Forecast, db.C("weather"))
	cmds.Event("*", f)

	// Add our muxes to the bot
	c.Event("PRIVMSG", cmds)
	c.Event("PRIVMSG", ment)

	// Things to do on connect
	c.EventFunc("001", func(c *irc.Client, e *irc.Event) {
		for _, v := range config.Cmds {
			c.Write(v)
		}
	})

	if config.TLS {
		// Have to work around self signed ssl cert
		conf := &tls.Config{
			InsecureSkipVerify: config.TLSNoVerify,
		}

		c.DialTLS(config.Host, conf)
	} else {
		c.Dial(config.Host)
	}
}
<commit_msg>Adds back missing plugin to the base seabird<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"
	"path"

	"labix.org/v2/mgo"

	"bitbucket.org/belak/go-seabird"
	"bitbucket.org/belak/irc"
	"bitbucket.org/belak/irc/mux"
)

type Config struct {
	Prefix string

	// Bot info
	Nick string
	User string
	Name string
	Pass string

	// Host
	Host        string
	TLS         bool
	TLSNoVerify bool

	// Cmds for on connect
	Cmds []string

	// Plugin config
	Plugins struct {
		Forecast string
	}
}

func init() {
	// Try HOME first then fall back to user.Current() because it needs cgo
	home := os.Getenv("HOME")
	if home == "" {
		user, err := user.Current()
		if err != nil {
			log.Fatalln(err)
		}
		home = user.HomeDir
	}

	flag.StringVar(&configFile, "F", path.Join(home, ".seabird", "main.json"), "alternate config file")
}

var configFile string

func loadConfig(filename string) *Config {
	file, err := os.Open(filename)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	config := &Config{}
	dec := json.NewDecoder(file)
	dec.Decode(config)

	return config
}

func main() {
	// Command line options
	flag.Parse()

	// Load the config file
	config := loadConfig(configFile)

	c := irc.NewClient(config.Nick, config.User, config.Name, config.Pass)

	// Connect to mongo
	sess, err := mgo.Dial("localhost")
	if err != nil {
		fmt.Println(err)
		return
	}

	db := sess.DB("seabird")

	// Add seabird
	cmds := mux.NewCommandMux(config.Prefix)
	ment := mux.NewMentionMux()

	// Coin Kick
	cmds.ChannelFunc("coin", seabird.CoinKickHandler)

	// URL stuff
	c.EventFunc("PRIVMSG", seabird.URLHandler)

	// Dice rolling
	ment.EventFunc(seabird.DiceHandler)

	// Mentions
	ment.EventFunc(seabird.MentionsHandler)

	// Add karma
	k := seabird.NewKarmaHandler(db.C("karma"))
	cmds.EventFunc("karma", k.Karma)
	c.EventFunc("PRIVMSG", k.Msg)

	// Add forecast
	f := seabird.NewForecastHandler(config.Plugins.Forecast, db.C("weather"))
	cmds.Event("*", f)

	// Add our muxes to the bot
	c.Event("PRIVMSG", cmds)
	c.Event("PRIVMSG", ment)

	// Things to do on connect
	c.EventFunc("001", func(c *irc.Client, e *irc.Event) {
		for _, v := range config.Cmds {
			c.Write(v)
		}
	})

	if config.TLS {
		// Have to work around self signed ssl cert
		conf := &tls.Config{
			InsecureSkipVerify: config.TLSNoVerify,
		}

		c.DialTLS(config.Host, conf)
	} else {
		c.Dial(config.Host)
	}
}
<|endoftext|>


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

// Package heap provides heap operations for any type that implements
// heap.Interface.
//
package heap

import "sort"

// Any type that implements heap.Interface may be used as a
// min-heap with the following invariants (established after
// Init has been called):
//
//	!h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
//
type Interface interface {
	sort.Interface
	Push(x interface{})
	Pop() interface{}
}

// A heap must be initialized before any of the heap operations
// can be used. Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// Its complexity is O(n) where n = h.Len().
//
func Init(h Interface) {
	// heapify
	n := h.Len()
	for i := n/2 - 1; i >= 0; i-- {
		down(h, i, n)
	}
}

// Push pushes the element x onto the heap. The complexity is
// O(log(n)) where n = h.Len().
//
func Push(h Interface, x interface{}) {
	h.Push(x)
	up(h, h.Len()-1)
}

// Pop removes the minimum element (according to Less) from the heap
// and returns it. The complexity is O(log(n)) where n = h.Len().
// Same as Remove(h, 0).
//
func Pop(h Interface) interface{} {
	n := h.Len() - 1
	h.Swap(0, n)
	down(h, 0, n)
	return h.Pop()
}

// Remove removes the element at index i from the heap.
// The complexity is O(log(n)) where n = h.Len().
//
func Remove(h Interface, i int) interface{} {
	n := h.Len() - 1
	if n != i {
		h.Swap(i, n)
		down(h, i, n)
		up(h, i)
	}
	return h.Pop()
}

func up(h Interface, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || h.Less(i, j) {
			break
		}
		h.Swap(i, j)
		j = i
	}
}

func down(h Interface, i, n int) {
	for {
		j1 := 2*i + 1
		if j1 >= n {
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
			j = j2 // = 2*i + 2  // right child
		}
		if h.Less(i, j) {
			break
		}
		h.Swap(i, j)
		i = j
	}
}
<commit_msg>container/heap: document what Push and Pop do<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package heap provides heap operations for any type that implements
// heap.Interface.
//
package heap

import "sort"

// Any type that implements heap.Interface may be used as a
// min-heap with the following invariants (established after
// Init has been called or if the data is empty or sorted):
//
//	!h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
//
// Note that Push and Pop in this interface are for package heap's
// implementation to call.  To add and remove things from the heap,
// use heap.Push and heap.Pop.
type Interface interface {
	sort.Interface
	Push(x interface{}) // add x as element Len()
	Pop() interface{}   // remove and return element Len() - 1.
}

// A heap must be initialized before any of the heap operations
// can be used. Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// Its complexity is O(n) where n = h.Len().
//
func Init(h Interface) {
	// heapify
	n := h.Len()
	for i := n/2 - 1; i >= 0; i-- {
		down(h, i, n)
	}
}

// Push pushes the element x onto the heap. The complexity is
// O(log(n)) where n = h.Len().
//
func Push(h Interface, x interface{}) {
	h.Push(x)
	up(h, h.Len()-1)
}

// Pop removes the minimum element (according to Less) from the heap
// and returns it. The complexity is O(log(n)) where n = h.Len().
// Same as Remove(h, 0).
//
func Pop(h Interface) interface{} {
	n := h.Len() - 1
	h.Swap(0, n)
	down(h, 0, n)
	return h.Pop()
}

// Remove removes the element at index i from the heap.
// The complexity is O(log(n)) where n = h.Len().
//
func Remove(h Interface, i int) interface{} {
	n := h.Len() - 1
	if n != i {
		h.Swap(i, n)
		down(h, i, n)
		up(h, i)
	}
	return h.Pop()
}

func up(h Interface, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || h.Less(i, j) {
			break
		}
		h.Swap(i, j)
		j = i
	}
}

func down(h Interface, i, n int) {
	for {
		j1 := 2*i + 1
		if j1 >= n {
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
			j = j2 // = 2*i + 2  // right child
		}
		if h.Less(i, j) {
			break
		}
		h.Swap(i, j)
		i = j
	}
}
<|endoftext|>


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

// This file contains the exported entry points for invoking the parser.

package parser

import (
	"bytes"
	"go/ast"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
)

// If src != nil, readSource converts src to a []byte if possible;
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
func readSource(filename string, src interface{}) ([]byte, os.Error) {
	if src != nil {
		switch s := src.(type) {
		case string:
			return []byte(s), nil
		case []byte:
			return s, nil
		case *bytes.Buffer:
			// is io.Reader, but src is already available in []byte form
			if s != nil {
				return s.Bytes(), nil
			}
		case io.Reader:
			var buf bytes.Buffer
			_, err := io.Copy(&buf, s)
			if err != nil {
				return nil, err
			}
			return buf.Bytes(), nil
		default:
			return nil, os.ErrorString("invalid source")
		}
	}

	return ioutil.ReadFile(filename)
}

func (p *parser) parseEOF() os.Error {
	p.expect(token.EOF)
	return p.GetError(scanner.Sorted)
}

// ParseExpr parses a Go expression and returns the corresponding
// AST node. The fset, filename, and src arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression
// may be nil or contain a partial AST.
//
func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	x := p.parseExpr()
	if p.tok == token.SEMICOLON {
		p.next() // consume automatically inserted semicolon, if any
	}
	return x, p.parseEOF()
}

// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	return p.parseStmtList(), p.parseEOF()
}

// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	return p.parseDeclList(), p.parseEOF()
}

// TODO(gri) Change ParseFile to Parse and improve documentation (issue 1311).

// ParseFile parses a Go source file and returns a File node.
//
// If src != nil, ParseFile parses the file source from src. src may
// be provided in a variety of formats. At the moment the following types
// are supported: string, []byte, and io.Reader. In this case, filename is
// only used for source position information and error messages.
//
// If src == nil, ParseFile parses the file specified by filename.
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality. Position information is recorded in the
// file set fset.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.BadX nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, mode)
	return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
}

// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
// bits are passed to ParseFile unchanged. Position information is recorded
// in the file set fset.
//
// Files with parse errors are ignored. In this case the map of packages may
// be incomplete (missing packages and/or incomplete packages) and the first
// error encountered is returned.
//
func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
	pkgs = make(map[string]*ast.Package)
	for _, filename := range filenames {
		if src, err := ParseFile(fset, filename, nil, mode); err == nil {
			name := src.Name.Name
			pkg, found := pkgs[name]
			if !found {
				pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
				pkgs[name] = pkg
			}
			pkg.Files[filename] = src
		} else if first == nil {
			first = err
		}
	}
	return
}

// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
// are considered. The mode bits are passed to ParseFile unchanged. Position
// information is recorded in the file set fset.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occured, a non-nil but incomplete map and the
// error are returned.
//
func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
	fd, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	list, err := fd.Readdir(-1)
	if err != nil {
		return nil, err
	}

	filenames := make([]string, len(list))
	n := 0
	for i := 0; i < len(list); i++ {
		d := &list[i]
		if filter == nil || filter(d) {
			filenames[n] = pathutil.Join(path, d.Name)
			n++
		}
	}
	filenames = filenames[0:n]

	return ParseFiles(fset, filenames, mode)
}
<commit_msg>go/parser: Better comment for ParseFile.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains the exported entry points for invoking the parser.

package parser

import (
	"bytes"
	"go/ast"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
)

// If src != nil, readSource converts src to a []byte if possible;
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
func readSource(filename string, src interface{}) ([]byte, os.Error) {
	if src != nil {
		switch s := src.(type) {
		case string:
			return []byte(s), nil
		case []byte:
			return s, nil
		case *bytes.Buffer:
			// is io.Reader, but src is already available in []byte form
			if s != nil {
				return s.Bytes(), nil
			}
		case io.Reader:
			var buf bytes.Buffer
			_, err := io.Copy(&buf, s)
			if err != nil {
				return nil, err
			}
			return buf.Bytes(), nil
		default:
			return nil, os.ErrorString("invalid source")
		}
	}

	return ioutil.ReadFile(filename)
}

func (p *parser) parseEOF() os.Error {
	p.expect(token.EOF)
	return p.GetError(scanner.Sorted)
}

// ParseExpr parses a Go expression and returns the corresponding
// AST node. The fset, filename, and src arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression
// may be nil or contain a partial AST.
//
func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	x := p.parseExpr()
	if p.tok == token.SEMICOLON {
		p.next() // consume automatically inserted semicolon, if any
	}
	return x, p.parseEOF()
}

// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	return p.parseStmtList(), p.parseEOF()
}

// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, 0)
	return p.parseDeclList(), p.parseEOF()
}

// ParseFile parses the source code of a single Go source file and returns
// the corresponding ast.File node. The source code may be provided via
// the filename of the source file, or via the src parameter.
//
// If src != nil, ParseFile parses the source from src and the filename is
// only used when recording position information. The type of the argument
// for the src parameter must be string, []byte, or io.Reader.
//
// If src == nil, ParseFile parses the file specified by filename.
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality. Position information is recorded in the
// file set fset.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.BadX nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(fset, filename, data, mode)
	return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
}

// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
// bits are passed to ParseFile unchanged. Position information is recorded
// in the file set fset.
//
// Files with parse errors are ignored. In this case the map of packages may
// be incomplete (missing packages and/or incomplete packages) and the first
// error encountered is returned.
//
func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
	pkgs = make(map[string]*ast.Package)
	for _, filename := range filenames {
		if src, err := ParseFile(fset, filename, nil, mode); err == nil {
			name := src.Name.Name
			pkg, found := pkgs[name]
			if !found {
				pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
				pkgs[name] = pkg
			}
			pkg.Files[filename] = src
		} else if first == nil {
			first = err
		}
	}
	return
}

// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
// are considered. The mode bits are passed to ParseFile unchanged. Position
// information is recorded in the file set fset.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occured, a non-nil but incomplete map and the
// error are returned.
//
func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
	fd, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	list, err := fd.Readdir(-1)
	if err != nil {
		return nil, err
	}

	filenames := make([]string, len(list))
	n := 0
	for i := 0; i < len(list); i++ {
		d := &list[i]
		if filter == nil || filter(d) {
			filenames[n] = pathutil.Join(path, d.Name)
			n++
		}
	}
	filenames = filenames[0:n]

	return ParseFiles(fset, filenames, mode)
}
<|endoftext|>


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

import "testing"

const N = 20

func BenchmarkAppend(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, j)
		}
	}
}

func BenchmarkAppendSpecialCase(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			if len(x) < cap(x) {
				x = x[:len(x)+1]
				x[len(x)-1] = j
			} else {
				x = append(x, j)
			}
		}
	}
}

var x = make([]int, 0, 10)

func f() int {
	x[:1][0] = 3
	return 2
}

func TestSideEffectOrder(t *testing.T) {
	x = append(x, 1, f())
	if x[0] != 1 || x[1] != 2 {
		t.Error("append failed: ", x[0], x[1])
	}
}
<commit_msg>runtime: make TestSideEffectOrder work twice<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime_test

import "testing"

const N = 20

func BenchmarkAppend(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, j)
		}
	}
}

func BenchmarkAppendSpecialCase(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			if len(x) < cap(x) {
				x = x[:len(x)+1]
				x[len(x)-1] = j
			} else {
				x = append(x, j)
			}
		}
	}
}

var x []int

func f() int {
	x[:1][0] = 3
	return 2
}

func TestSideEffectOrder(t *testing.T) {
	x = make([]int, 0, 10)
	x = append(x, 1, f())
	if x[0] != 1 || x[1] != 2 {
		t.Error("append failed: ", x[0], x[1])
	}
}
<|endoftext|>