<commit_before>// Copyright 2015 Tim Heckman. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.

// Package flock implements a thread-safe sync.Locker interface for file locking.
// It also includes a non-blocking TryLock() function to allow locking
// without blocking execution.
//
// Package flock is released under the BSD 3-Clause License. See the LICENSE file
// for more details.
package flock

import (
	"os"
	"sync"
	"syscall"
)

// Flock is the struct type to handle file locking. All fields are unexported,
// with access to some of the fields provided by getter methods (Path() and Locked()).
type Flock struct {
	path string
	m    sync.RWMutex
	fh   *os.File
	l    bool
}

// NewFlock is a function to return a new instance of *Flock. The only parameter
// it takes is the path to the desired lockfile.
func NewFlock(path string) *Flock {
	return &Flock{path: path}
}

// Path is a function to return the path as provided in NewFlock().
func (f *Flock) Path() string {
	return f.path
}

// Locked is a function to return the current lock state (locked: true, unlocked: false).
func (f *Flock) Locked() bool {
	f.m.RLock()
	defer f.m.RUnlock()
	return f.l
}

// Lock is a blocking call to try and take the file lock. It will wait until it
// is able to obtain the exclusive file lock. It's recommended that TryLock() be
// used over this function. This function may block the ability to query the
// current Locked() status due to a RW-mutex lock.
//
// If we are already locked, this function short-circuits and returns immediately
// assuming it can take the mutex lock.
func (f *Flock) Lock() error {
	f.m.Lock()
	defer f.m.Unlock()

	if f.fh == nil {
		if err := f.setFh(); err != nil {
			return err
		}
	}

	if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX); err != nil {
		return err
	}

	f.l = true
	return nil
}

// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
// while it is running the Locked() function will be blocked.
//
// This function short-circuits if we are unlocked already. If not, it calls
// syscall.LOCK_UN on the file, closes the file descriptor, and removes the file
// from disk. If the removal is successful, it also marks the *os.File instance
// for GC by setting it to nil.
func (f *Flock) Unlock() error {
	f.m.Lock()
	defer f.m.Unlock()

	// if we aren't locked or if the lockfile instance is nil
	// just return a nil error because we are unlocked
	if !f.l || f.fh == nil {
		return nil
	}

	// release the lock
	if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
		return err
	}

	f.l = false

	// close the file descriptor
	// and remove the file from disk
	f.fh.Close()
	err := os.Remove(f.fh.Name())

	// if we removed the file properly: make the handler nil
	if err == nil {
		f.fh = nil
	}

	return err
}

// TryLock is the preferred function for taking a file lock. This function does
// take a RW-mutex lock before it tries to lock the file, so there is the
// possibility that this function may block for a short time if another goroutine
// is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the exclusive
// file lock, the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being locked.
func (f *Flock) TryLock() (bool, error) {
	f.m.Lock()
	defer f.m.Unlock()

	if f.l {
		return true, nil
	}

	if f.fh == nil {
		if err := f.setFh(); err != nil {
			return false, err
		}
	}

	err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)

	switch err {
	case syscall.EWOULDBLOCK:
		return false, nil
	case nil:
		f.l = true
		return true, nil
	}

	return false, err
}

func (f *Flock) setFh() error {
	// open a new os.File instance
	// create it if it doesn't exist, truncate it if it does exist, open the file read-write
	fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.FileMode(0600))

	if err != nil {
		return err
	}

	// set the filehandle on the struct
	f.fh = fh
	return nil
}
<commit_msg>when unlocking make the filehandle nil<commit_after>// Copyright 2015 Tim Heckman. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.

// Package flock implements a thread-safe sync.Locker interface for file locking.
// It also includes a non-blocking TryLock() function to allow locking
// without blocking execution.
//
// Package flock is released under the BSD 3-Clause License. See the LICENSE file
// for more details.
package flock

import (
	"os"
	"sync"
	"syscall"
)

// Flock is the struct type to handle file locking. All fields are unexported,
// with access to some of the fields provided by getter methods (Path() and Locked()).
type Flock struct {
	path string
	m    sync.RWMutex
	fh   *os.File
	l    bool
}

// NewFlock is a function to return a new instance of *Flock. The only parameter
// it takes is the path to the desired lockfile.
func NewFlock(path string) *Flock {
	return &Flock{path: path}
}

// Path is a function to return the path as provided in NewFlock().
func (f *Flock) Path() string {
	return f.path
}

// Locked is a function to return the current lock state (locked: true, unlocked: false).
func (f *Flock) Locked() bool {
	f.m.RLock()
	defer f.m.RUnlock()
	return f.l
}

// Lock is a blocking call to try and take the file lock. It will wait until it
// is able to obtain the exclusive file lock. It's recommended that TryLock() be
// used over this function. This function may block the ability to query the
// current Locked() status due to a RW-mutex lock.
//
// If we are already locked, this function short-circuits and returns immediately
// assuming it can take the mutex lock.
func (f *Flock) Lock() error {
	f.m.Lock()
	defer f.m.Unlock()

	if f.fh == nil {
		if err := f.setFh(); err != nil {
			return err
		}
	}

	if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX); err != nil {
		return err
	}

	f.l = true
	return nil
}

// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
// while it is running the Locked() function will be blocked.
//
// This function short-circuits if we are unlocked already. If not, it calls
// syscall.LOCK_UN on the file, closes the file descriptor, and removes the file
// from disk. If the removal is successful, it also marks the *os.File instance
// for GC by setting it to nil.
func (f *Flock) Unlock() error {
	f.m.Lock()
	defer f.m.Unlock()

	// if we aren't locked or if the lockfile instance is nil
	// just return a nil error because we are unlocked
	if !f.l || f.fh == nil {
		return nil
	}

	// release the lock
	if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
		return err
	}

	f.l = false

	// close the file descriptor
	// and remove the file from disk
	f.fh.Close()
	err := os.Remove(f.fh.Name())

	f.fh = nil

	return err
}

// TryLock is the preferred function for taking a file lock. This function does
// take a RW-mutex lock before it tries to lock the file, so there is the
// possibility that this function may block for a short time if another goroutine
// is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the exclusive
// file lock, the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being locked.
func (f *Flock) TryLock() (bool, error) {
	f.m.Lock()
	defer f.m.Unlock()

	if f.l {
		return true, nil
	}

	if f.fh == nil {
		if err := f.setFh(); err != nil {
			return false, err
		}
	}

	err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)

	switch err {
	case syscall.EWOULDBLOCK:
		return false, nil
	case nil:
		f.l = true
		return true, nil
	}

	return false, err
}

func (f *Flock) setFh() error {
	// open a new os.File instance
	// create it if it doesn't exist, truncate it if it does exist, open the file read-write
	fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.FileMode(0600))

	if err != nil {
		return err
	}

	// set the filehandle on the struct
	f.fh = fh
	return nil
}
<|endoftext|>


<commit_before>package gateway

import (
	"fmt"
	"testing"

	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/storage"
	"github.com/lonelycode/osin"
	"github.com/stretchr/testify/assert"
)

const (
	RevokeOauthHashedToken        = "RevokeOauthHashedToken"
	RevokeOauthToken              = "RevokeOauthToken"
	RevokeOauthRefreshToken       = "RevokeOauthRefreshToken"
	RevokeOauthRefreshHashedToken = "RevokeOauthRefreshHashedToken" // we do  not support hashed refresh tokens yet

	DefaultOrg = "default-org-id"
)

func buildStringEvent(eventType, token, apiId string) string {
	switch eventType {
	case RevokeOauthHashedToken:
		// string is as= {the-hashed-token}#hashed:{api-id}:oAuthRevokeToken
		token = storage.HashStr(token)
		return fmt.Sprintf("%s#hashed:%s:oAuthRevokeToken", token, apiId)
	case RevokeOauthToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeToken", token, apiId)
	case RevokeOauthRefreshToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeRefreshToken", token, apiId)
	case RevokeOauthRefreshHashedToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeToken", token, apiId)
	}
	return ""
}

func getAccessToken(td tokenData) string {
	return td.AccessToken
}

func getRefreshToken(td tokenData) string {
	return td.RefreshToken
}

func TestProcessKeySpaceChangesForOauth(t *testing.T) {

	cases := []struct {
		TestName string
		Event    string
		Hashed   bool
		GetToken func(td tokenData) string
	}{
		{
			TestName: RevokeOauthToken,
			Event:    RevokeOauthToken,
			Hashed:   false,
			GetToken: getAccessToken,
		},
		{
			TestName: RevokeOauthHashedToken,
			Event:    RevokeOauthHashedToken,
			Hashed:   true,
			GetToken: getAccessToken,
		},
		{
			TestName: RevokeOauthRefreshToken,
			Event:    RevokeOauthRefreshToken,
			Hashed:   false,
			GetToken: getRefreshToken,
		},
	}

	for _, tc := range cases {
		t.Run(tc.TestName, func(t *testing.T) {
			ts := StartTest()
			defer ts.Close()

			globalConf := config.Global()
			globalConf.HashKeys = tc.Hashed
			config.SetGlobal(globalConf)

			rpcListener := RPCStorageHandler{
				KeyPrefix:        "rpc.listener.",
				SuppressRegister: true,
				HashKeys:         tc.Hashed,
			}

			myApi := loadTestOAuthSpec()
			oauthClient := createTestOAuthClient(myApi, authClientID)
			tokenData := getToken(t, ts)
			token := tc.GetToken(tokenData)

			var getKeyFromStore func(string) (string, error)
			if tc.Event == RevokeOauthRefreshToken {
				//Refresh token are threated in a different way due that they reside in a different level and we cannot access them directly
				client := new(OAuthClient)
				client.MetaData = oauthClient.MetaData
				client.Description = oauthClient.Description
				client.ClientSecret = oauthClient.GetSecret()
				client.PolicyID = oauthClient.PolicyID
				client.ClientRedirectURI = oauthClient.ClientRedirectURI

				storage := myApi.OAuthManager.OsinServer.Storage
				ret := &osin.AccessData{
					AccessToken:  tokenData.AccessToken,
					RefreshToken: tokenData.RefreshToken,
					Client:       client,
				}
				storage.SaveAccess(ret)

				getKeyFromStore = func(token string) (string, error) {
					accessData, err := storage.LoadRefresh(token)
					var refresh string
					if accessData != nil {
						refresh = accessData.RefreshToken
					}
					return refresh, err
				}
			} else {
				getKeyFromStore = GlobalSessionManager.Store().GetKey
				GlobalSessionManager.Store().DeleteAllKeys()
				GlobalSessionManager.Store().SetKey(token, token, 100)
				_, err := GlobalSessionManager.Store().GetKey(token)
				if err != nil {
					t.Fatal("Key should be pre-loaded in store previously so the test can perform the revoke action.")
				}
			}

			stringEvent := buildStringEvent(tc.Event, token, myApi.APIID)
			rpcListener.ProcessKeySpaceChanges([]string{stringEvent}, "")
			found, err := getKeyFromStore(token)
			if err == nil {
				t.Error(" key not removed. event:", stringEvent, " found:", found)
			} else {
				assert.Equal(t, err.Error(), "key not found", "expected error msg is 'key not found'")
			}
		})
	}
}
<commit_msg>update process KeySpace Changes call in tests (#3409)<commit_after>package gateway

import (
	"fmt"
	"testing"

	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/storage"
	"github.com/lonelycode/osin"
	"github.com/stretchr/testify/assert"
)

const (
	RevokeOauthHashedToken        = "RevokeOauthHashedToken"
	RevokeOauthToken              = "RevokeOauthToken"
	RevokeOauthRefreshToken       = "RevokeOauthRefreshToken"
	RevokeOauthRefreshHashedToken = "RevokeOauthRefreshHashedToken" // we do  not support hashed refresh tokens yet

	DefaultOrg = "default-org-id"
)

func buildStringEvent(eventType, token, apiId string) string {
	switch eventType {
	case RevokeOauthHashedToken:
		// string is as= {the-hashed-token}#hashed:{api-id}:oAuthRevokeToken
		token = storage.HashStr(token)
		return fmt.Sprintf("%s#hashed:%s:oAuthRevokeToken", token, apiId)
	case RevokeOauthToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeToken", token, apiId)
	case RevokeOauthRefreshToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeRefreshToken", token, apiId)
	case RevokeOauthRefreshHashedToken:
		// string is as= {the-token}:{api-id}:oAuthRevokeToken
		return fmt.Sprintf("%s:%s:oAuthRevokeToken", token, apiId)
	}
	return ""
}

func getAccessToken(td tokenData) string {
	return td.AccessToken
}

func getRefreshToken(td tokenData) string {
	return td.RefreshToken
}

func TestProcessKeySpaceChangesForOauth(t *testing.T) {

	cases := []struct {
		TestName string
		Event    string
		Hashed   bool
		GetToken func(td tokenData) string
	}{
		{
			TestName: RevokeOauthToken,
			Event:    RevokeOauthToken,
			Hashed:   false,
			GetToken: getAccessToken,
		},
		{
			TestName: RevokeOauthHashedToken,
			Event:    RevokeOauthHashedToken,
			Hashed:   true,
			GetToken: getAccessToken,
		},
		{
			TestName: RevokeOauthRefreshToken,
			Event:    RevokeOauthRefreshToken,
			Hashed:   false,
			GetToken: getRefreshToken,
		},
	}

	for _, tc := range cases {
		t.Run(tc.TestName, func(t *testing.T) {
			ts := StartTest()
			defer ts.Close()

			globalConf := config.Global()
			globalConf.HashKeys = tc.Hashed
			config.SetGlobal(globalConf)

			rpcListener := RPCStorageHandler{
				KeyPrefix:        "rpc.listener.",
				SuppressRegister: true,
				HashKeys:         tc.Hashed,
			}

			myApi := loadTestOAuthSpec()
			oauthClient := createTestOAuthClient(myApi, authClientID)
			tokenData := getToken(t, ts)
			token := tc.GetToken(tokenData)

			var getKeyFromStore func(string) (string, error)
			if tc.Event == RevokeOauthRefreshToken {
				//Refresh token are threated in a different way due that they reside in a different level and we cannot access them directly
				client := new(OAuthClient)
				client.MetaData = oauthClient.MetaData
				client.Description = oauthClient.Description
				client.ClientSecret = oauthClient.GetSecret()
				client.PolicyID = oauthClient.PolicyID
				client.ClientRedirectURI = oauthClient.ClientRedirectURI

				storage := myApi.OAuthManager.OsinServer.Storage
				ret := &osin.AccessData{
					AccessToken:  tokenData.AccessToken,
					RefreshToken: tokenData.RefreshToken,
					Client:       client,
				}
				storage.SaveAccess(ret)

				getKeyFromStore = func(token string) (string, error) {
					accessData, err := storage.LoadRefresh(token)
					var refresh string
					if accessData != nil {
						refresh = accessData.RefreshToken
					}
					return refresh, err
				}
			} else {
				getKeyFromStore = GlobalSessionManager.Store().GetKey
				GlobalSessionManager.Store().DeleteAllKeys()
				GlobalSessionManager.Store().SetKey(token, token, 100)
				_, err := GlobalSessionManager.Store().GetKey(token)
				if err != nil {
					t.Fatal("Key should be pre-loaded in store previously so the test can perform the revoke action.")
				}
			}

			stringEvent := buildStringEvent(tc.Event, token, myApi.APIID)
			rpcListener.ProcessKeySpaceChanges([]string{stringEvent}, myApi.OrgID)
			found, err := getKeyFromStore(token)
			if err == nil {
				t.Error(" key not removed. event:", stringEvent, " found:", found)
			} else {
				assert.Equal(t, err.Error(), "key not found", "expected error msg is 'key not found'")
			}
		})
	}
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Arnaud Vazard
//
// See LICENSE file.
package database

import (
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"os"
)

func NewDatabase(databaseName string, reset bool) *sql.DB {
	// Use default name if not specified
	if databaseName == "" {
		// check if the storage directory exist, if not create it
		storage, err := os.Stat("./storage")
		if err != nil {
			os.Mkdir("./storage", os.ModeDir)
		} else if !storage.IsDir() {
			// check if the storage is indeed a directory or not
			log.Fatal("\"storage\" exist but is not a directory")
		}
		databaseName = "./storage/db.sqlite"
	}

	if reset {
		os.Remove(databaseName)
	}

	db, err := sql.Open("sqlite3", databaseName)
	if err != nil {
		log.Fatal(err)
	}
	return db
}
<commit_msg>Database: Added comments<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Arnaud Vazard
//
// See LICENSE file.

// Database management
package database

import (
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"os"
)

// Database constructor.
// If database name is an empty string the default path will be used ("./storage/db.sqlite"),
//else it will be used as the path for the database file.
// If reset is true destroy the database before opening it (which will recreate it).
func NewDatabase(databaseName string, reset bool) *sql.DB {
	// Use default name if not specified
	if databaseName == "" {
		// check if the storage directory exist, if not create it
		storage, err := os.Stat("./storage")
		if err != nil {
			os.Mkdir("./storage", os.ModeDir)
		} else if !storage.IsDir() {
			// check if the storage is indeed a directory or not
			log.Fatal("\"storage\" exist but is not a directory")
		}
		databaseName = "./storage/db.sqlite"
	}
	if reset {
		os.Remove(databaseName)
	}
	db, err := sql.Open("sqlite3", databaseName)
	if err != nil {
		log.Fatal(err)
	}
	return db
}
<|endoftext|>


<commit_before>package database

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"fmt"
)

type Bot struct {
	gorm.Model
	Link     string
	Header   string
	Body     string
	Form     string
	PostForm string
	RemoteIp string
}

type PasteText struct {
	gorm.Model
	Code string `gorm:"primary_key"`
	Text string `gorm:"size:999999999"`
}

type DatabaseConnection struct {
	*gorm.DB
}
//TODO: https://github.com/mattn/go-sqlite3/issues/214
func NewSqlite3(databasePath string) *DatabaseConnection {
	db, err := gorm.Open("sqlite3", databasePath)
	if err != nil {
		panic("failed to connect database sqlite, error: " + err.Error())
	}
	// Migrate the schema
	return &DatabaseConnection{db}
}

func NewMySQL(host string, port int, login string, password string, dbname string) *DatabaseConnection {
	scheme_url := fmt.Sprintf("%v:%v@tcp(%v:%d)/%v?charset=utf8&parseTime=True&loc=Local", login, password, host, port, dbname)
	fmt.Println(scheme_url)
	db, err := gorm.Open("mysql", scheme_url)
	if err != nil {
		panic("failed to connect database mysql, error: " + err.Error())
	}
	// Migrate the schema
	return &DatabaseConnection{db}
}

func (db *DatabaseConnection) GetUrls() (bots []Bot) {
	db.Find(&bots)
	return bots;
}

func (db *DatabaseConnection) AddUrl(bot *Bot) {
	db.Create(bot)
}

func (db *DatabaseConnection) AddText(text *PasteText) {
	db.Create(text)
}

func (db *DatabaseConnection) GetText(code string) (text PasteText) {
	db.Where("code = ?", code).First(&text)
	return text;
}<commit_msg>fix size text.<commit_after>package database

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"fmt"
)

type Bot struct {
	gorm.Model
	Link     string `gorm:"size:999999999"`
	Header   string `gorm:"size:999999999"`
	Body     string `gorm:"size:999999999"`
	Form     string `gorm:"size:999999999"`
	PostForm string `gorm:"size:999999999"`
	RemoteIp string
}

type PasteText struct {
	gorm.Model
	Code string `gorm:"primary_key"`
	Text string `gorm:"size:999999999"`
}

type DatabaseConnection struct {
	*gorm.DB
}
//TODO: https://github.com/mattn/go-sqlite3/issues/214
func NewSqlite3(databasePath string) *DatabaseConnection {
	db, err := gorm.Open("sqlite3", databasePath)
	if err != nil {
		panic("failed to connect database sqlite, error: " + err.Error())
	}
	// Migrate the schema
	return &DatabaseConnection{db}
}

func NewMySQL(host string, port int, login string, password string, dbname string) *DatabaseConnection {
	scheme_url := fmt.Sprintf("%v:%v@tcp(%v:%d)/%v?charset=utf8&parseTime=True&loc=Local", login, password, host, port, dbname)
	fmt.Println(scheme_url)
	db, err := gorm.Open("mysql", scheme_url)
	if err != nil {
		panic("failed to connect database mysql, error: " + err.Error())
	}
	// Migrate the schema
	return &DatabaseConnection{db}
}

func (db *DatabaseConnection) GetUrls() (bots []Bot) {
	db.Find(&bots)
	return bots;
}

func (db *DatabaseConnection) AddUrl(bot *Bot) {
	db.Create(bot)
}

func (db *DatabaseConnection) AddText(text *PasteText) {
	db.Create(text)
}

func (db *DatabaseConnection) GetText(code string) (text PasteText) {
	db.Where("code = ?", code).First(&text)
	return text;
}<|endoftext|>


<commit_before>package useful

import (
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

// For ease of use.
const (
	Byte     = 1
	B        = Byte
	Kilobyte = 1024 * Byte
	KB       = Kilobyte
	Megabyte = 1024 * Kilobyte
	MB       = Megabyte
	Gigabyte = 1024 * Megabyte
	GB       = Gigabyte
	Terabyte = 1024 * Gigabyte
	TB       = Terabyte
)

type dest uint8

// Locations for log writing.
const (
	Stdout dest = iota
	Stderr
	File
	Both
)

// archPrefix is the temporary archive file's prefix before
// randName appends a random string of digits to the end.
const archPrefix = "._archive"

// Options is the structure containing the options for a given Log.
type Options struct {
	// LogFormat determines the format of the log. Most standard
	// formats found in Apache's mod_log_config docs are supported.
	LogFormat LogFmt

	// LogDestination determines where the Handler will write to.
	// By default it writes to Stdout and LogName.
	LogDestination dest

	// LogName is the name of the log the handler will write to.
	// It defaults to "access.log", but can be set to anything you
	// want.
	LogName string

	// ArchiveDir is the directory where the archives will be stored.
	// If set to "" (empty string) it'll be set to the current directory.
	// It defaults to "archives", so it'll look a little something like
	// this: '/home/user/files/archives/'
	ArchiveDir string

	// MaxFileSize is the maximum size of a log file in bytes.
	// It defaults to 1 Gigabyte (multiple of 1024, not 1000),
	// but can be set to anything you want.
	//
	// Log files larger than this size will be compressed into
	// archive files.
	MaxFileSize int64
}

var (
	// LogFile is the active Log.
	LogFile *Log

	// cur is the current log iteration. E.g., if there are 10
	// archived logs, cur will be 11.
	cur int64
)

// Log is a structure with our open file we log to, the size of said file
// (measured by the number of bytes written to it, or it's size on
// initialization), our current writer (usually Stdout and the
// aforementioned file), our pool of random names, and a mutex lock
// to keep race conditions from tripping us up.
type Log struct {
	Opts        *Options  // Current log options.
	file        *os.File  // Pointer to the open file.
	size        int64     // Number of bytes written to filel.
	out         io.Writer // Current io.Writer.
	pool        *randPool // Pool of random names.
	*sync.Mutex           // Mutex for locking.
}

// Init sets LogFile and starts the check for 'cur'.
func (l *Log) Init(opts *Options) {
	if l == nil {
		var err error
		l, err = NewLog(opts)
		if err != nil {
			panic(err)
		}
	}
	LogFile = l
	LogFile.Start()
}

// NewLog returns a new Log initialized to the default values.
// If no log file exists with the name specified in 'LogName'
// it'll create a new one, otherwise it opens 'LogName'.
// If it cannot create or open a file it'll return nil for *Log
// and the applicable error.
func NewLog(opts *Options) (*Log, error) {
	if opts == nil {
		opts = DefaultOptions()
	}

	log := &Log{
		Opts: opts,
	}

	file, err := log.newFile()
	if err != nil {
		return nil, err
	}

	stat, err := file.Stat()

	var size int64
	if err == nil {
		size = stat.Size()
	}

	log.file = file
	log.size = size
	log.SetWriter()
	log.pool = newRandPool(25)
	log.Mutex = &sync.Mutex{}

	return log, nil
}

// DefaultOptions returns the default configuration for the Options
// structure.
func DefaultOptions() *Options {
	return &Options{
		LogFormat:      CommonLog,
		LogDestination: Both,
		LogName:        "access.log",
		ArchiveDir:     "archives",
		MaxFileSize:    100 * Byte,
	}
}

// newFile returns a 'new' file to write logs to.
// It's simply a wrapper around os.OpenFile.
// While it says 'new', it'll return an already existing log file
// if one exists.
func (l *Log) newFile() (file *os.File, err error) {
	file, err = os.OpenFile(l.Opts.LogName,
		os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
	return
}

// Start begins the check for 'cur'.
// TOOD: Implement this better.
func (l *Log) Start() {

	// Check for the current archive log number. It *should* be fine
	// inside a Goroutine because, unless there's a *ton* of archive
	// files and the current Log is just shy of MaxFileSize, it'll
	// finish before Log fills up and needs to be rotated.
	l.findCur()
}

// findCur finds the current archive log number. If any errors occur it'll
// panic because this needs refactoring.
func (l *Log) findCur() {
	dir, err := os.Open(l.Opts.ArchiveDir)
	if err != nil {
		panic(err)
	}
	defer dir.Close()

	names, err := dir.Readdirnames(-1)

	// 0 names means the directory is empty, so cur *has* to be 0.
	if len(names) == 0 {
		cur = 0
		return
	}

	// Sort the strings. Our naming scheme, "#%02d_" will allow us to
	// select the last string in the slice once it's ordered
	// in increasing order.
	sort.Strings(names)

	highest := names[len(names)-1]

	// Okay, we've found some gzipped files.
	if !strings.HasSuffix(highest, "_.gz") {
		cur = 0
		return
	}

	h := strings.LastIndex(highest, "#")
	if h == -1 {
		panic("Could not find current file number.")
	}

	u := strings.LastIndex(highest[:], "_")
	if u == -1 {
		panic("Could not find current file number.")
	}

	cur, err = strconv.ParseInt(highest[h+1:u-1], 10, 64)
	if err != nil {
		panic(err)
	}
}

// Rotate will rotate the logs so that the current (theoretically
// full) log will be compressed and added to the archive and a new
// log generated.
// Will panic if we cannot replace our physical file.
// (See newFile function for more information.)
func (l *Log) Rotate() {
	var err error

	// For speed.
	randName := l.pool.get()

	// Rename so we can release our lock on the file asap.
	os.Rename(LogFile.Opts.LogName, randName)

	// Replace our physical file.
	l.file, err = l.newFile()
	if err != nil {
		panic(err)
	}

	// Reset the size.
	l.size = 0

	// Reset the writer (underlying io.Writer would otherwise point to the
	// fd of the old, renamed file).
	l.SetWriter()

	// Place the used name back into the pool for future use.
	l.pool.put(randName)

	go l.doRotate(randName)
}

func (l *Log) doRotate(randName string) {
	// From here on out we don't need to worry about time because we've
	// already moved the Log file and created a new, unlocked one for
	// our handler to write to.
	path := filepath.Join(l.Opts.ArchiveDir, l.Opts.LogName)

	// E.g., "access.log_01.gz"
	// We throw in the underscore before the number to try to help
	// identify our numbering scheme even if the user picks a wacky
	// file that includes numbers and stuff.
	archiveName := fmt.Sprintf("%s#%010d_.gz", path, cur)
	cur++

	archive, err := os.Create(archiveName)
	if err != nil {
		panic(err)
	}
	defer archive.Close()

	oldLog, err := os.Open(randName)
	if err != nil {
		panic(err)
	}
	defer oldLog.Close()

	gzw, err := gzip.NewWriterLevel(archive, gzip.BestCompression)
	if err != nil {
		panic(err)
	}
	defer gzw.Close()

	_, err = io.Copy(gzw, oldLog)
	if err != nil {
		panic(err)
	}

	err = os.Remove(randName)
	if err != nil {
		panic(err)
	}
}

// Close closes the Log file.
func (l *Log) Close() {
	l.Lock()
	defer l.Unlock()

	l.file.Close()
}

// SetWriter sets Log's writer depending on LogDestination.
func (l *Log) SetWriter() {

	logMap := map[dest]io.Writer{
		Stdout: os.Stdout,
		Stderr: os.Stderr,
		File:   l.file,
		Both:   io.MultiWriter(os.Stdout, l.file),
	}

	l.out = logMap[l.Opts.LogDestination]
}

// randPool is a pool of random names used for rotating log files.
type randPool struct {
	c chan string
	*sync.Mutex
}

// newRandPool creates a new pool of random names and immediately
// initializes the pool with N new names.
func newRandPool(n int) *randPool {
	pool := &randPool{
		make(chan string, n),
		&sync.Mutex{},
	}

	for i := 0; i < n; i++ {
		pool.put(randName(archPrefix))
	}

	return pool
}

// get gets a name from the pool, or generates a new name if none
// exist.
func (p *randPool) get() (s string) {
	p.Lock()
	defer p.Unlock()

	select {
	case s = <-p.c:
		// get a name from the pool
	default:
		return randName(archPrefix)
	}
	return
}

// put puts a new name (back) into the pool, or discards it if the pool
// is full.
func (p *randPool) put(s string) {
	p.Lock()
	defer p.Unlock()

	select {
	case p.c <- s:
		// place back into pool
	default:
		// discard if pool is full
	}
}

// Borrowed from https://golang.org/src/io/ioutil/tempfile.go#L19

var rand uint32
var randmu sync.Mutex

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	randmu.Lock()
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	randmu.Unlock()
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

func randName(prefix string) (name string) {
	nconflict := 0
	for i := 0; i < 10000; i++ {
		name = prefix + nextSuffix()
		_, err := os.Stat(name)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}
<commit_msg>updated max fle size<commit_after>package useful

import (
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

// For ease of use.
const (
	Byte     = 1
	B        = Byte
	Kilobyte = 1024 * Byte
	KB       = Kilobyte
	Megabyte = 1024 * Kilobyte
	MB       = Megabyte
	Gigabyte = 1024 * Megabyte
	GB       = Gigabyte
	Terabyte = 1024 * Gigabyte
	TB       = Terabyte
)

type dest uint8

// Locations for log writing.
const (
	Stdout dest = iota
	Stderr
	File
	Both
)

// archPrefix is the temporary archive file's prefix before
// randName appends a random string of digits to the end.
const archPrefix = "._archive"

// Options is the structure containing the options for a given Log.
type Options struct {
	// LogFormat determines the format of the log. Most standard
	// formats found in Apache's mod_log_config docs are supported.
	LogFormat LogFmt

	// LogDestination determines where the Handler will write to.
	// By default it writes to Stdout and LogName.
	LogDestination dest

	// LogName is the name of the log the handler will write to.
	// It defaults to "access.log", but can be set to anything you
	// want.
	LogName string

	// ArchiveDir is the directory where the archives will be stored.
	// If set to "" (empty string) it'll be set to the current directory.
	// It defaults to "archives", so it'll look a little something like
	// this: '/home/user/files/archives/'
	ArchiveDir string

	// MaxFileSize is the maximum size of a log file in bytes.
	// It defaults to 1 Gigabyte (multiple of 1024, not 1000),
	// but can be set to anything you want.
	//
	// Log files larger than this size will be compressed into
	// archive files.
	MaxFileSize int64
}

var (
	// LogFile is the active Log.
	LogFile *Log

	// cur is the current log iteration. E.g., if there are 10
	// archived logs, cur will be 11.
	cur int64
)

// Log is a structure with our open file we log to, the size of said file
// (measured by the number of bytes written to it, or it's size on
// initialization), our current writer (usually Stdout and the
// aforementioned file), our pool of random names, and a mutex lock
// to keep race conditions from tripping us up.
type Log struct {
	Opts        *Options  // Current log options.
	file        *os.File  // Pointer to the open file.
	size        int64     // Number of bytes written to filel.
	out         io.Writer // Current io.Writer.
	pool        *randPool // Pool of random names.
	*sync.Mutex           // Mutex for locking.
}

// Init sets LogFile and starts the check for 'cur'.
func (l *Log) Init(opts *Options) {
	if l == nil {
		var err error
		l, err = NewLog(opts)
		if err != nil {
			panic(err)
		}
	}
	LogFile = l
	LogFile.Start()
}

// NewLog returns a new Log initialized to the default values.
// If no log file exists with the name specified in 'LogName'
// it'll create a new one, otherwise it opens 'LogName'.
// If it cannot create or open a file it'll return nil for *Log
// and the applicable error.
func NewLog(opts *Options) (*Log, error) {
	if opts == nil {
		opts = DefaultOptions()
	}

	log := &Log{
		Opts: opts,
	}

	file, err := log.newFile()
	if err != nil {
		return nil, err
	}

	stat, err := file.Stat()

	var size int64
	if err == nil {
		size = stat.Size()
	}

	log.file = file
	log.size = size
	log.SetWriter()
	log.pool = newRandPool(25)
	log.Mutex = &sync.Mutex{}

	return log, nil
}

// DefaultOptions returns the default configuration for the Options
// structure.
func DefaultOptions() *Options {
	return &Options{
		LogFormat:      CommonLog,
		LogDestination: Both,
		LogName:        "access.log",
		ArchiveDir:     "archives",
		MaxFileSize:    1 * Gigabyte,
	}
}

// newFile returns a 'new' file to write logs to.
// It's simply a wrapper around os.OpenFile.
// While it says 'new', it'll return an already existing log file
// if one exists.
func (l *Log) newFile() (file *os.File, err error) {
	file, err = os.OpenFile(l.Opts.LogName,
		os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644)
	return
}

// Start begins the check for 'cur'.
// TOOD: Implement this better.
func (l *Log) Start() {

	// Check for the current archive log number. It *should* be fine
	// inside a Goroutine because, unless there's a *ton* of archive
	// files and the current Log is just shy of MaxFileSize, it'll
	// finish before Log fills up and needs to be rotated.
	l.findCur()
}

// findCur finds the current archive log number. If any errors occur it'll
// panic because this needs refactoring.
func (l *Log) findCur() {
	dir, err := os.Open(l.Opts.ArchiveDir)
	if err != nil {
		panic(err)
	}
	defer dir.Close()

	names, err := dir.Readdirnames(-1)

	// 0 names means the directory is empty, so cur *has* to be 0.
	if len(names) == 0 {
		cur = 0
		return
	}

	// Sort the strings. Our naming scheme, "#%02d_" will allow us to
	// select the last string in the slice once it's ordered
	// in increasing order.
	sort.Strings(names)

	highest := names[len(names)-1]

	// Okay, we've found some gzipped files.
	if !strings.HasSuffix(highest, "_.gz") {
		cur = 0
		return
	}

	h := strings.LastIndex(highest, "#")
	if h == -1 {
		panic("Could not find current file number.")
	}

	u := strings.LastIndex(highest[:], "_")
	if u == -1 {
		panic("Could not find current file number.")
	}

	cur, err = strconv.ParseInt(highest[h+1:u-1], 10, 64)
	if err != nil {
		panic(err)
	}
}

// Rotate will rotate the logs so that the current (theoretically
// full) log will be compressed and added to the archive and a new
// log generated.
// Will panic if we cannot replace our physical file.
// (See newFile function for more information.)
func (l *Log) Rotate() {
	var err error

	// For speed.
	randName := l.pool.get()

	// Rename so we can release our lock on the file asap.
	os.Rename(LogFile.Opts.LogName, randName)

	// Replace our physical file.
	l.file, err = l.newFile()
	if err != nil {
		panic(err)
	}

	// Reset the size.
	l.size = 0

	// Reset the writer (underlying io.Writer would otherwise point to the
	// fd of the old, renamed file).
	l.SetWriter()

	// Place the used name back into the pool for future use.
	l.pool.put(randName)

	go l.doRotate(randName)
}

func (l *Log) doRotate(randName string) {
	// From here on out we don't need to worry about time because we've
	// already moved the Log file and created a new, unlocked one for
	// our handler to write to.
	path := filepath.Join(l.Opts.ArchiveDir, l.Opts.LogName)

	// E.g., "access.log_01.gz"
	// We throw in the underscore before the number to try to help
	// identify our numbering scheme even if the user picks a wacky
	// file that includes numbers and stuff.
	archiveName := fmt.Sprintf("%s#%010d_.gz", path, cur)
	cur++

	archive, err := os.Create(archiveName)
	if err != nil {
		panic(err)
	}
	defer archive.Close()

	oldLog, err := os.Open(randName)
	if err != nil {
		panic(err)
	}
	defer oldLog.Close()

	gzw, err := gzip.NewWriterLevel(archive, gzip.BestCompression)
	if err != nil {
		panic(err)
	}
	defer gzw.Close()

	_, err = io.Copy(gzw, oldLog)
	if err != nil {
		panic(err)
	}

	err = os.Remove(randName)
	if err != nil {
		panic(err)
	}
}

// Close closes the Log file.
func (l *Log) Close() {
	l.Lock()
	defer l.Unlock()

	l.file.Close()
}

// SetWriter sets Log's writer depending on LogDestination.
func (l *Log) SetWriter() {

	logMap := map[dest]io.Writer{
		Stdout: os.Stdout,
		Stderr: os.Stderr,
		File:   l.file,
		Both:   io.MultiWriter(os.Stdout, l.file),
	}

	l.out = logMap[l.Opts.LogDestination]
}

// randPool is a pool of random names used for rotating log files.
type randPool struct {
	c chan string
	*sync.Mutex
}

// newRandPool creates a new pool of random names and immediately
// initializes the pool with N new names.
func newRandPool(n int) *randPool {
	pool := &randPool{
		make(chan string, n),
		&sync.Mutex{},
	}

	for i := 0; i < n; i++ {
		pool.put(randName(archPrefix))
	}

	return pool
}

// get gets a name from the pool, or generates a new name if none
// exist.
func (p *randPool) get() (s string) {
	p.Lock()
	defer p.Unlock()

	select {
	case s = <-p.c:
		// get a name from the pool
	default:
		return randName(archPrefix)
	}
	return
}

// put puts a new name (back) into the pool, or discards it if the pool
// is full.
func (p *randPool) put(s string) {
	p.Lock()
	defer p.Unlock()

	select {
	case p.c <- s:
		// place back into pool
	default:
		// discard if pool is full
	}
}

// Borrowed from https://golang.org/src/io/ioutil/tempfile.go#L19

var rand uint32
var randmu sync.Mutex

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	randmu.Lock()
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	randmu.Unlock()
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

func randName(prefix string) (name string) {
	nconflict := 0
	for i := 0; i < 10000; i++ {
		name = prefix + nextSuffix()
		_, err := os.Stat(name)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}
<|endoftext|>


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

// +build ignore

package main

import (
	"math"

	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/utl"
)

func main() {

	// scalar field
	fcn := func(x, y float64) float64 {
		return -math.Pow(math.Pow(math.Cos(x), 2.0)+math.Pow(math.Cos(y), 2.0), 2.0)
	}

	// gradient. u=dfdx, v=dfdy
	grad := func(x, y float64) (u, v float64) {
		m := math.Pow(math.Cos(x), 2.0) + math.Pow(math.Cos(y), 2.0)
		u = 4.0 * math.Cos(x) * math.Sin(x) * m
		v = 4.0 * math.Cos(y) * math.Sin(y) * m
		return
	}

	// grid size
	xmin, xmax, N := -math.Pi/2.0+0.1, math.Pi/2.0-0.1, 21

	// mesh grid
	X, Y := utl.MeshGrid2d(xmin, xmax, xmin, xmax, N, N)

	// compute f(x,y) and components of gradient
	F := utl.DblsAlloc(N, N)
	U := utl.DblsAlloc(N, N)
	V := utl.DblsAlloc(N, N)
	for i := 0; i < N; i++ {
		for j := 0; j < N; j++ {
			F[i][j] = fcn(X[i][j], Y[i][j])
			U[i][j], V[i][j] = grad(X[i][j], Y[i][j])
		}
	}

	// plot
	plt.Reset(false, nil)
	plt.ContourF(X, Y, F, &plt.A{CmapIdx: 4}) // "levels=20, cmapidx=4")
	plt.Quiver(X, Y, U, V, &plt.A{C: "r"})
	plt.Gll("x", "y", nil)
	plt.Equal()
	plt.Save("/tmp/gosl", "plt_contour01")
}
<commit_msg>Improve example with HL meshgrid function<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"math"

	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/utl"
)

func main() {

	// grid size
	xmin, xmax, N := -math.Pi/2.0+0.1, math.Pi/2.0-0.1, 21

	// mesh grid, scalar and vector field
	X, Y, F, U, V := utl.MeshGrid2dFG(xmin, xmax, xmin, xmax, N, N, func(x, y float64) (f, u, v float64) {

		// scalar field
		m := math.Pow(math.Cos(x), 2.0) + math.Pow(math.Cos(y), 2.0)
		f = -math.Pow(m, 2.0)

		// gradient. u=dfdx, v=dfdy
		u = 4.0 * math.Cos(x) * math.Sin(x) * m
		v = 4.0 * math.Cos(y) * math.Sin(y) * m
		return
	})

	// plot
	plt.Reset(false, nil)
	plt.ContourF(X, Y, F, &plt.A{CmapIdx: 4, Nlevels: 15})
	plt.Quiver(X, Y, U, V, &plt.A{C: "r"})
	plt.Gll("x", "y", nil)
	plt.Equal()
	plt.Save("/tmp/gosl", "plt_contour01")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"

	"github.com/RichardKnop/machinery/_examples/tasks"
	machinery "github.com/RichardKnop/machinery/v1"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/errors"
)

// Define flags
var (
	configPath    = flag.String("c", "config.yml", "Path to a configuration file")
	broker        = flag.String("b", "amqp://guest:guest@localhost:5672/", "Broker URL")
	resultBackend = flag.String("r", "amqp://guest:guest@localhost:5672/", "Result backend")
	exchange      = flag.String("e", "machinery_exchange", "Durable, non-auto-deleted AMQP exchange name")
	exchangeType  = flag.String("t", "direct", "Exchange type - direct|fanout|topic|x-custom")
	defaultQueue  = flag.String("q", "machinery_tasks", "Ephemeral AMQP queue name")
	bindingKey    = flag.String("k", "machinery_task", "AMQP binding key")

	cnf    config.Config
	server *machinery.Server
	worker *machinery.Worker
)

func init() {
	// Parse the flags
	flag.Parse()

	cnf = config.Config{
		Broker:        *broker,
		ResultBackend: *resultBackend,
		Exchange:      *exchange,
		ExchangeType:  *exchangeType,
		DefaultQueue:  *defaultQueue,
		BindingKey:    *bindingKey,
	}

	// Parse the config
	// NOTE: If a config file is present, it has priority over flags
	data, err := config.ReadFromFile(*configPath)
	if err == nil {
		err = config.ParseYAMLConfig(&data, &cnf)
		errors.Fail(err, "Could not parse config file")
	}

	server, err := machinery.NewServer(&cnf)
	errors.Fail(err, "Could not initialize server")

	// Register tasks
	tasks := map[string]interface{}{
		"add":      exampletasks.Add,
		"multiply": exampletasks.Multiply,
	}
	server.RegisterTasks(tasks)

	// The second argument is a consumer tag
	// Ideally, each worker should have a unique tag (worker1, worker2 etc)
	worker = server.NewWorker("machinery_worker")
}

func main() {
	err := worker.Launch()
	errors.Fail(err, "Could not launch worker")
}
<commit_msg>Fixed broken import in examples.<commit_after>package main

import (
	"flag"

	"github.com/RichardKnop/machinery/examples/tasks"
	machinery "github.com/RichardKnop/machinery/v1"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/errors"
)

// Define flags
var (
	configPath    = flag.String("c", "config.yml", "Path to a configuration file")
	broker        = flag.String("b", "amqp://guest:guest@localhost:5672/", "Broker URL")
	resultBackend = flag.String("r", "amqp://guest:guest@localhost:5672/", "Result backend")
	exchange      = flag.String("e", "machinery_exchange", "Durable, non-auto-deleted AMQP exchange name")
	exchangeType  = flag.String("t", "direct", "Exchange type - direct|fanout|topic|x-custom")
	defaultQueue  = flag.String("q", "machinery_tasks", "Ephemeral AMQP queue name")
	bindingKey    = flag.String("k", "machinery_task", "AMQP binding key")

	cnf    config.Config
	server *machinery.Server
	worker *machinery.Worker
)

func init() {
	// Parse the flags
	flag.Parse()

	cnf = config.Config{
		Broker:        *broker,
		ResultBackend: *resultBackend,
		Exchange:      *exchange,
		ExchangeType:  *exchangeType,
		DefaultQueue:  *defaultQueue,
		BindingKey:    *bindingKey,
	}

	// Parse the config
	// NOTE: If a config file is present, it has priority over flags
	data, err := config.ReadFromFile(*configPath)
	if err == nil {
		err = config.ParseYAMLConfig(&data, &cnf)
		errors.Fail(err, "Could not parse config file")
	}

	server, err := machinery.NewServer(&cnf)
	errors.Fail(err, "Could not initialize server")

	// Register tasks
	tasks := map[string]interface{}{
		"add":      exampletasks.Add,
		"multiply": exampletasks.Multiply,
	}
	server.RegisterTasks(tasks)

	// The second argument is a consumer tag
	// Ideally, each worker should have a unique tag (worker1, worker2 etc)
	worker = server.NewWorker("machinery_worker")
}

func main() {
	err := worker.Launch()
	errors.Fail(err, "Could not launch worker")
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The libusb developers. All rights reserved.
// Project site: https://github.com/gotmc/libusb
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package libusb

// #cgo pkg-config: libusb-1.0
// #include <libusb.h>
import "C"
import (
	"reflect"
	"unsafe"
)

// DeviceHandle represents the libusb device handle.
type DeviceHandle struct {
	libusbDeviceHandle *C.libusb_device_handle
}

func (dh *DeviceHandle) GetStringDescriptor(
	descIndex uint8,
	langID uint16,
) (string, error) {
	var data *C.uchar
	length := 512
	usberr := C.libusb_get_string_descriptor(
		dh.libusbDeviceHandle,
		C.uint8_t(descIndex),
		C.uint16_t(langID),
		data,
		C.int(length),
	)
	if usberr < 0 {
		return "", ErrorCode(usberr)
	}
	return "Yes!!!", nil
}

func (dh *DeviceHandle) GetStringDescriptorASCII(descIndex uint8) (string, error) {
	length := 256
	data := make([]byte, length)
	usberr := C.libusb_get_string_descriptor_ascii(
		dh.libusbDeviceHandle,
		C.uint8_t(descIndex),
		// Unsafe pointer -> http://stackoverflow.com/a/16376039/95592
		(*C.uchar)(unsafe.Pointer(&data[0])),
		C.int(length),
	)
	if usberr < 0 {
		return "", ErrorCode(usberr)
	}
	return string(data), nil
}

// Close implements libusb_close to close the device handle.
func (dh *DeviceHandle) Close() error {
	C.libusb_close(dh.libusbDeviceHandle)
	return nil
}

// GetDevice implements libusb_get_device to get the underlying device for a
// handle.
// TODO(mdr): Determine if I actually need this function.
// func (dh *DeviceHandle) GetDevice() (*Device, error) {
// }

// GetConfiguration implements the libusb_get_configuration function to
// determine the bConfigurationValue of the currently active configuration.
func (dh *DeviceHandle) GetConfiguration() (int, error) {
	var configuration *C.int
	err := C.libusb_get_configuration(dh.libusbDeviceHandle, configuration)
	if err != 0 {
		return 0, ErrorCode(err)
	}
	return int(*configuration), nil
}

// SetConfiguration implements libusb_set_configuration to set the active
// configuration for the device.
func (dh *DeviceHandle) SetConfiguration(configuration int) error {
	err := C.libusb_set_configuration(dh.libusbDeviceHandle,
		C.int(configuration))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// ClaimInterface implements libusb_claim_interface to claim an interface on a
// given device handle. You must claim the interface you wish to use before you
// can perform I/O on any of its endpoints.
func (dh *DeviceHandle) ClaimInterface(interfaceNum int) error {
	err := C.libusb_claim_interface(dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// ReleaseInterface implements libusb_release_interface to release an interface
// previously claimed with libusb_claim_interface() (i.e., ClaimInterface()).
func (dh *DeviceHandle) ReleaseInterface(interfaceNum int) error {
	err := C.libusb_release_interface(dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

func (dh *DeviceHandle) SetInterfaceAltSetting(
	interfaceNum int,
	alternateSetting int,
) error {
	err := C.libusb_set_interface_alt_setting(
		dh.libusbDeviceHandle,
		C.int(interfaceNum),
		C.int(alternateSetting),
	)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// FIXME(mdr): libusb_clear_halt takes an endpoint as an unsigned char. Need to
// determine, what I should pass into this function as the endpoint.
// func (dh *DeviceHandle) ClearHalt(endpoint int) error {
// return nil
// }

// ResetDevice implements libusb_reset_device to perform a USB port reset to
// reinitialize a device.
func (dh *DeviceHandle) ResetDevice() error {
	err := C.libusb_reset_device(dh.libusbDeviceHandle)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// KernelDriverActive implements libusb_kernel_driver_active to determine if a
// kernel driver is active on an interface.
func (dh *DeviceHandle) KernelDriverActive(interfaceNum int) error {
	err := C.libusb_kernel_driver_active(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// DetachKernelDriver implements libusb_detach_kernel_driver to detach a kernel
// driver from an interface.
func (dh *DeviceHandle) DetachKernelDriver(interfaceNum int) error {
	err := C.libusb_detach_kernel_driver(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// AttachKernelDriver implements libusb_attach_kernel_driver to re-attach an
// interface's kernel driver, which was previously detached using
// libusb_detach_kernel_driver().
func (dh *DeviceHandle) AttachKernelDriver(interfaceNum int) error {
	err := C.libusb_attach_kernel_driver(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// SetAutoDetachKernelDriver implements libusb_set_auto_detach_kernel_driver to
// enable/disable libusb's automatic kernel driver detachment.
func (dh *DeviceHandle) SetAutoDetachKernelDriver(enable bool) error {
	cEnable := C.int(0)
	if enable == true {
		cEnable = C.int(1)
	}
	err := C.libusb_set_auto_detach_kernel_driver(dh.libusbDeviceHandle, cEnable)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

func (dh *DeviceHandle) BulkTransfer(
	endpoint endpointAddress,
	data []byte,
	length int,
	timeout int,
) (int, error) {
	// var transferred *C.int
	// err := C.libusb_bulk_transfer(
	// dh.libusbDeviceHandle,
	// C.uchar(endpoint),
	// (*C.uchar)(unsafe.Pointer(&data[0])),
	// C.int(length),
	// transferred,
	// C.uint(timeout),
	// )

	cData := (*reflect.SliceHeader)(unsafe.Pointer(&data)).Data

	var transferred C.int
	err := C.libusb_bulk_transfer(
		dh.libusbDeviceHandle,
		C.uchar(endpoint),
		(*C.uchar)(unsafe.Pointer(cData)),
		C.int(len(data)),
		&transferred,
		C.uint(timeout),
	)
	if err != 0 {
		return 0, ErrorCode(err)
	}
	return int(transferred), nil
}
<commit_msg>Modified GetStringDescriptor()<commit_after>// Copyright (c) 2015 The libusb developers. All rights reserved.
// Project site: https://github.com/gotmc/libusb
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package libusb

// #cgo pkg-config: libusb-1.0
// #include <libusb.h>
import "C"
import (
	"reflect"
	"unsafe"
)

// DeviceHandle represents the libusb device handle.
type DeviceHandle struct {
	libusbDeviceHandle *C.libusb_device_handle
}

func (dh *DeviceHandle) GetStringDescriptor(
	descIndex uint8,
	langID uint16,
) (string, error) {
	var cData *C.uchar
	length := 512
	usberr := C.libusb_get_string_descriptor(
		dh.libusbDeviceHandle,
		C.uint8_t(descIndex),
		C.uint16_t(langID),
		cData,
		C.int(length),
	)
	if usberr < 0 {
		return "", ErrorCode(usberr)
	}
	data := (*C.char)(unsafe.Pointer(cData))
	return C.GoString(data), nil
}

func (dh *DeviceHandle) GetStringDescriptorASCII(
	descIndex uint8,
) (string, error) {
	length := 256
	data := make([]byte, length)
	usberr := C.libusb_get_string_descriptor_ascii(
		dh.libusbDeviceHandle,
		C.uint8_t(descIndex),
		// Unsafe pointer -> http://stackoverflow.com/a/16376039/95592
		(*C.uchar)(unsafe.Pointer(&data[0])),
		C.int(length),
	)
	if usberr < 0 {
		return "", ErrorCode(usberr)
	}
	return string(data), nil
}

// Close implements libusb_close to close the device handle.
func (dh *DeviceHandle) Close() error {
	C.libusb_close(dh.libusbDeviceHandle)
	return nil
}

// GetDevice implements libusb_get_device to get the underlying device for a
// handle.
// TODO(mdr): Determine if I actually need this function.
// func (dh *DeviceHandle) GetDevice() (*Device, error) {
// }

// GetConfiguration implements the libusb_get_configuration function to
// determine the bConfigurationValue of the currently active configuration.
func (dh *DeviceHandle) GetConfiguration() (int, error) {
	var configuration *C.int
	err := C.libusb_get_configuration(dh.libusbDeviceHandle, configuration)
	if err != 0 {
		return 0, ErrorCode(err)
	}
	return int(*configuration), nil
}

// SetConfiguration implements libusb_set_configuration to set the active
// configuration for the device.
func (dh *DeviceHandle) SetConfiguration(configuration int) error {
	err := C.libusb_set_configuration(dh.libusbDeviceHandle,
		C.int(configuration))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// ClaimInterface implements libusb_claim_interface to claim an interface on a
// given device handle. You must claim the interface you wish to use before you
// can perform I/O on any of its endpoints.
func (dh *DeviceHandle) ClaimInterface(interfaceNum int) error {
	err := C.libusb_claim_interface(dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// ReleaseInterface implements libusb_release_interface to release an interface
// previously claimed with libusb_claim_interface() (i.e., ClaimInterface()).
func (dh *DeviceHandle) ReleaseInterface(interfaceNum int) error {
	err := C.libusb_release_interface(dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

func (dh *DeviceHandle) SetInterfaceAltSetting(
	interfaceNum int,
	alternateSetting int,
) error {
	err := C.libusb_set_interface_alt_setting(
		dh.libusbDeviceHandle,
		C.int(interfaceNum),
		C.int(alternateSetting),
	)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// FIXME(mdr): libusb_clear_halt takes an endpoint as an unsigned char. Need to
// determine, what I should pass into this function as the endpoint.
// func (dh *DeviceHandle) ClearHalt(endpoint int) error {
// return nil
// }

// ResetDevice implements libusb_reset_device to perform a USB port reset to
// reinitialize a device.
func (dh *DeviceHandle) ResetDevice() error {
	err := C.libusb_reset_device(dh.libusbDeviceHandle)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// KernelDriverActive implements libusb_kernel_driver_active to determine if a
// kernel driver is active on an interface.
func (dh *DeviceHandle) KernelDriverActive(interfaceNum int) error {
	err := C.libusb_kernel_driver_active(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// DetachKernelDriver implements libusb_detach_kernel_driver to detach a kernel
// driver from an interface.
func (dh *DeviceHandle) DetachKernelDriver(interfaceNum int) error {
	err := C.libusb_detach_kernel_driver(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// AttachKernelDriver implements libusb_attach_kernel_driver to re-attach an
// interface's kernel driver, which was previously detached using
// libusb_detach_kernel_driver().
func (dh *DeviceHandle) AttachKernelDriver(interfaceNum int) error {
	err := C.libusb_attach_kernel_driver(
		dh.libusbDeviceHandle, C.int(interfaceNum))
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

// SetAutoDetachKernelDriver implements libusb_set_auto_detach_kernel_driver to
// enable/disable libusb's automatic kernel driver detachment.
func (dh *DeviceHandle) SetAutoDetachKernelDriver(enable bool) error {
	cEnable := C.int(0)
	if enable == true {
		cEnable = C.int(1)
	}
	err := C.libusb_set_auto_detach_kernel_driver(dh.libusbDeviceHandle, cEnable)
	if err != 0 {
		return ErrorCode(err)
	}
	return nil
}

func (dh *DeviceHandle) BulkTransfer(
	endpoint endpointAddress,
	data []byte,
	length int,
	timeout int,
) (int, error) {
	// var transferred *C.int
	// err := C.libusb_bulk_transfer(
	// dh.libusbDeviceHandle,
	// C.uchar(endpoint),
	// (*C.uchar)(unsafe.Pointer(&data[0])),
	// C.int(length),
	// transferred,
	// C.uint(timeout),
	// )

	cData := (*reflect.SliceHeader)(unsafe.Pointer(&data)).Data

	var transferred C.int
	err := C.libusb_bulk_transfer(
		dh.libusbDeviceHandle,
		C.uchar(endpoint),
		(*C.uchar)(unsafe.Pointer(cData)),
		C.int(len(data)),
		&transferred,
		C.uint(timeout),
	)
	if err != 0 {
		return 0, ErrorCode(err)
	}
	return int(transferred), nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Dataence, LLC. 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 message

import (
	"encoding/binary"
	"fmt"
)

var (
	gPacketId uint64 = 0
)

// Fixed header
// - 1 byte for control packet type (bits 7-4) and flags (bits 3-0)
// - up to 4 byte for remaining length
type header struct {
	// Header fields
	//mtype  MessageType
	//flags  byte
	remlen int32

	// mtypeflags is the first byte of the buffer, 4 bits for mtype, 4 bits for flags
	mtypeflags []byte

	// Some messages need packet ID, 2 byte uint16
	packetId []byte

	// Points to the decoding buffer
	dbuf []byte

	// Whether the message has changed since last decode
	dirty bool
}

// String returns a string representation of the message.
func (this header) String() string {
	return fmt.Sprintf("Type=%q, Flags=%08b, Remaining Length=%d", this.Type().Name(), this.Flags(), this.remlen)
}

// Name returns a string representation of the message type. Examples include
// "PUBLISH", "SUBSCRIBE", and others. This is statically defined for each of
// the message types and cannot be changed.
func (this *header) Name() string {
	return this.Type().Name()
}

// Desc returns a string description of the message type. For example, a
// CONNECT message would return "Client request to connect to Server." These
// descriptions are statically defined (copied from the MQTT spec) and cannot
// be changed.
func (this *header) Desc() string {
	return this.Type().Desc()
}

// Type returns the MessageType of the Message. The retured value should be one
// of the constants defined for MessageType.
func (this *header) Type() MessageType {
	//return this.mtype
	if len(this.mtypeflags) != 1 {
		this.mtypeflags = make([]byte, 1)
		this.dirty = true
	}

	return MessageType(this.mtypeflags[0] >> 4)
}

// SetType sets the message type of this message. It also correctly sets the
// default flags for the message type. It returns an error if the type is invalid.
func (this *header) SetType(mtype MessageType) error {
	if !mtype.Valid() {
		return fmt.Errorf("header/SetType: Invalid control packet type %d", mtype)
	}

	// Notice we don't set the message to be dirty when we are not allocating a new
	// buffer. In this case, it means the buffer is probably a sub-slice of another
	// slice. If that's the case, then during encoding we would have copied the whole
	// backing buffer anyway.
	if len(this.mtypeflags) != 1 {
		this.mtypeflags = make([]byte, 1)
		this.dirty = true
	}

	this.mtypeflags[0] = byte(mtype)<<4 | (mtype.DefaultFlags() & 0xf)

	return nil
}

// Flags returns the fixed header flags for this message.
func (this *header) Flags() byte {
	//return this.flags
	return this.mtypeflags[0] & 0x0f
}

// RemainingLength returns the length of the non-fixed-header part of the message.
func (this *header) RemainingLength() int32 {
	return this.remlen
}

// SetRemainingLength sets the length of the non-fixed-header part of the message.
// It returns error if the length is greater than 268435455, which is the max
// message length as defined by the MQTT spec.
func (this *header) SetRemainingLength(remlen int32) error {
	if remlen > maxRemainingLength || remlen < 0 {
		return fmt.Errorf("header/SetLength: Remaining length (%d) out of bound (max %d, min 0)", remlen, maxRemainingLength)
	}

	this.remlen = remlen
	this.dirty = true

	return nil
}

func (this *header) Len() int {
	return this.msglen()
}

// PacketId returns the ID of the packet.
func (this *header) PacketId() uint16 {
	if len(this.packetId) == 2 {
		return binary.BigEndian.Uint16(this.packetId)
	}

	return 0
}

// SetPacketId sets the ID of the packet.
func (this *header) SetPacketId(v uint16) {
	// If setting to 0, nothing to do, move on
	if v == 0 {
		return
	}

	// If packetId buffer is not 2 bytes (uint16), then we allocate a new one and
	// make dirty. Then we encode the packet ID into the buffer.
	if len(this.packetId) != 2 {
		this.packetId = make([]byte, 2)
		this.dirty = true
	}

	// Notice we don't set the message to be dirty when we are not allocating a new
	// buffer. In this case, it means the buffer is probably a sub-slice of another
	// slice. If that's the case, then during encoding we would have copied the whole
	// backing buffer anyway.
	binary.BigEndian.PutUint16(this.packetId, v)
}

func (this *header) encode(dst []byte) (int, error) {
	ml := this.msglen()

	if len(dst) < ml {
		return 0, fmt.Errorf("header/Encode: Insufficient buffer size. Expecting %d, got %d.", ml, len(dst))
	}

	total := 0

	if this.remlen > maxRemainingLength || this.remlen < 0 {
		return total, fmt.Errorf("header/Encode: Remaining length (%d) out of bound (max %d, min 0)", this.remlen, maxRemainingLength)
	}

	if !this.Type().Valid() {
		return total, fmt.Errorf("header/Encode: Invalid message type %d", this.Type())
	}

	dst[total] = this.mtypeflags[0]
	total += 1

	n := binary.PutUvarint(dst[total:], uint64(this.remlen))
	total += n

	return total, nil
}

// Decode reads from the io.Reader parameter until a full message is decoded, or
// when io.Reader returns EOF or error. The first return value is the number of
// bytes read from io.Reader. The second is error if Decode encounters any problems.
func (this *header) decode(src []byte) (int, error) {
	total := 0

	this.dbuf = src

	mtype := this.Type()
	//mtype := MessageType(0)

	this.mtypeflags = src[total : total+1]
	//mtype := MessageType(src[total] >> 4)
	if !this.Type().Valid() {
		return total, fmt.Errorf("header/Decode: Invalid message type %d.", mtype)
	}

	if mtype != this.Type() {
		return total, fmt.Errorf("header/Decode: Invalid message type %d. Expecting %d.", this.Type(), mtype)
	}

	//this.flags = src[total] & 0x0f
	if this.Type() != PUBLISH && this.Flags() != this.Type().DefaultFlags() {
		return total, fmt.Errorf("header/Decode: Invalid message (%d) flags. Expecting %d, got %d", this.Type(), this.Type().DefaultFlags, this.Flags())
	}

	if this.Type() == PUBLISH && !ValidQos((this.Flags()>>1)&0x3) {
		return total, fmt.Errorf("header/Decode: Invalid QoS (%d) for PUBLISH message.", (this.Flags()>>1)&0x3)
	}

	total++

	remlen, m := binary.Uvarint(src[total:])
	total += m
	this.remlen = int32(remlen)

	if this.remlen > maxRemainingLength || remlen < 0 {
		return total, fmt.Errorf("header/Decode: Remaining length (%d) out of bound (max %d, min 0)", this.remlen, maxRemainingLength)
	}

	if int(this.remlen) > len(src[total:]) {
		return total, fmt.Errorf("header/Decode: Remaining length (%d) is greater than remaining buffer (%d)", this.remlen, len(src[total:]))
	}

	return total, nil
}

func (this *header) msglen() int {
	// message type and flag byte
	total := 1

	if this.remlen <= 127 {
		total += 1
	} else if this.remlen <= 16383 {
		total += 2
	} else if this.remlen <= 2097151 {
		total += 3
	} else {
		total += 4
	}

	return total
}
<commit_msg>Lots of documentation/comment updates<commit_after>// Copyright (c) 2014 Dataence, LLC. 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 message

import (
	"encoding/binary"
	"fmt"
)

var (
	gPacketId uint64 = 0
)

// Fixed header
// - 1 byte for control packet type (bits 7-4) and flags (bits 3-0)
// - up to 4 byte for remaining length
type header struct {
	// Header fields
	//mtype  MessageType
	//flags  byte
	remlen int32

	// mtypeflags is the first byte of the buffer, 4 bits for mtype, 4 bits for flags
	mtypeflags []byte

	// Some messages need packet ID, 2 byte uint16
	packetId []byte

	// Points to the decoding buffer
	dbuf []byte

	// Whether the message has changed since last decode
	dirty bool
}

// String returns a string representation of the message.
func (this header) String() string {
	return fmt.Sprintf("Type=%q, Flags=%08b, Remaining Length=%d", this.Type().Name(), this.Flags(), this.remlen)
}

// Name returns a string representation of the message type. Examples include
// "PUBLISH", "SUBSCRIBE", and others. This is statically defined for each of
// the message types and cannot be changed.
func (this *header) Name() string {
	return this.Type().Name()
}

// Desc returns a string description of the message type. For example, a
// CONNECT message would return "Client request to connect to Server." These
// descriptions are statically defined (copied from the MQTT spec) and cannot
// be changed.
func (this *header) Desc() string {
	return this.Type().Desc()
}

// Type returns the MessageType of the Message. The retured value should be one
// of the constants defined for MessageType.
func (this *header) Type() MessageType {
	//return this.mtype
	if len(this.mtypeflags) != 1 {
		this.mtypeflags = make([]byte, 1)
		this.dirty = true
	}

	return MessageType(this.mtypeflags[0] >> 4)
}

// SetType sets the message type of this message. It also correctly sets the
// default flags for the message type. It returns an error if the type is invalid.
func (this *header) SetType(mtype MessageType) error {
	if !mtype.Valid() {
		return fmt.Errorf("header/SetType: Invalid control packet type %d", mtype)
	}

	// Notice we don't set the message to be dirty when we are not allocating a new
	// buffer. In this case, it means the buffer is probably a sub-slice of another
	// slice. If that's the case, then during encoding we would have copied the whole
	// backing buffer anyway.
	if len(this.mtypeflags) != 1 {
		this.mtypeflags = make([]byte, 1)
		this.dirty = true
	}

	this.mtypeflags[0] = byte(mtype)<<4 | (mtype.DefaultFlags() & 0xf)

	return nil
}

// Flags returns the fixed header flags for this message.
func (this *header) Flags() byte {
	//return this.flags
	return this.mtypeflags[0] & 0x0f
}

// RemainingLength returns the length of the non-fixed-header part of the message.
func (this *header) RemainingLength() int32 {
	return this.remlen
}

// SetRemainingLength sets the length of the non-fixed-header part of the message.
// It returns error if the length is greater than 268435455, which is the max
// message length as defined by the MQTT spec.
func (this *header) SetRemainingLength(remlen int32) error {
	if remlen > maxRemainingLength || remlen < 0 {
		return fmt.Errorf("header/SetLength: Remaining length (%d) out of bound (max %d, min 0)", remlen, maxRemainingLength)
	}

	this.remlen = remlen
	this.dirty = true

	return nil
}

func (this *header) Len() int {
	return this.msglen()
}

// PacketId returns the ID of the packet.
func (this *header) PacketId() uint16 {
	if len(this.packetId) == 2 {
		return binary.BigEndian.Uint16(this.packetId)
	}

	return 0
}

// SetPacketId sets the ID of the packet.
func (this *header) SetPacketId(v uint16) {
	// If setting to 0, nothing to do, move on
	if v == 0 {
		return
	}

	// If packetId buffer is not 2 bytes (uint16), then we allocate a new one and
	// make dirty. Then we encode the packet ID into the buffer.
	if len(this.packetId) != 2 {
		this.packetId = make([]byte, 2)
		this.dirty = true
	}

	// Notice we don't set the message to be dirty when we are not allocating a new
	// buffer. In this case, it means the buffer is probably a sub-slice of another
	// slice. If that's the case, then during encoding we would have copied the whole
	// backing buffer anyway.
	binary.BigEndian.PutUint16(this.packetId, v)
}

func (this *header) encode(dst []byte) (int, error) {
	ml := this.msglen()

	if len(dst) < ml {
		return 0, fmt.Errorf("header/Encode: Insufficient buffer size. Expecting %d, got %d.", ml, len(dst))
	}

	total := 0

	if this.remlen > maxRemainingLength || this.remlen < 0 {
		return total, fmt.Errorf("header/Encode: Remaining length (%d) out of bound (max %d, min 0)", this.remlen, maxRemainingLength)
	}

	if !this.Type().Valid() {
		return total, fmt.Errorf("header/Encode: Invalid message type %d", this.Type())
	}

	dst[total] = this.mtypeflags[0]
	total += 1

	n := binary.PutUvarint(dst[total:], uint64(this.remlen))
	total += n

	return total, nil
}

// Decode reads from the io.Reader parameter until a full message is decoded, or
// when io.Reader returns EOF or error. The first return value is the number of
// bytes read from io.Reader. The second is error if Decode encounters any problems.
func (this *header) decode(src []byte) (int, error) {
	total := 0

	this.dbuf = src

	mtype := this.Type()
	//mtype := MessageType(0)

	this.mtypeflags = src[total : total+1]
	//mtype := MessageType(src[total] >> 4)
	if !this.Type().Valid() {
		return total, fmt.Errorf("header/Decode: Invalid message type %d.", mtype)
	}

	if mtype != this.Type() {
		return total, fmt.Errorf("header/Decode: Invalid message type %d. Expecting %d.", this.Type(), mtype)
	}

	//this.flags = src[total] & 0x0f
	if this.Type() != PUBLISH && this.Flags() != this.Type().DefaultFlags() {
		return total, fmt.Errorf("header/Decode: Invalid message (%d) flags. Expecting %d, got %d", this.Type(), this.Type().DefaultFlags(), this.Flags())
	}

	if this.Type() == PUBLISH && !ValidQos((this.Flags()>>1)&0x3) {
		return total, fmt.Errorf("header/Decode: Invalid QoS (%d) for PUBLISH message.", (this.Flags()>>1)&0x3)
	}

	total++

	remlen, m := binary.Uvarint(src[total:])
	total += m
	this.remlen = int32(remlen)

	if this.remlen > maxRemainingLength || remlen < 0 {
		return total, fmt.Errorf("header/Decode: Remaining length (%d) out of bound (max %d, min 0)", this.remlen, maxRemainingLength)
	}

	if int(this.remlen) > len(src[total:]) {
		return total, fmt.Errorf("header/Decode: Remaining length (%d) is greater than remaining buffer (%d)", this.remlen, len(src[total:]))
	}

	return total, nil
}

func (this *header) msglen() int {
	// message type and flag byte
	total := 1

	if this.remlen <= 127 {
		total += 1
	} else if this.remlen <= 16383 {
		total += 2
	} else if this.remlen <= 2097151 {
		total += 3
	} else {
		total += 4
	}

	return total
}
<|endoftext|>


<commit_before><commit_msg>localize var<commit_after><|endoftext|>


<commit_before>// Package db to connect to mongodb
package db

import (
	"errors"
	"fmt"
	"github.com/MG-RAST/Shock/shock-server/conf"
	"labix.org/v2/mgo"
	"os"
	"time"
)

const (
	DbTimeout = time.Duration(time.Second * 10)
)

var (
	Connection connection
)

type connection struct {
	dbname   string
	username string
	password string
	Session  *mgo.Session
	DB       *mgo.Database
}

func Initialize() (err error) {
	c := connection{}
	s, err := mgo.DialWithTimeout(conf.Conf["mongodb-hosts"], DbTimeout)
	if err != nil {
		e := errors.New(fmt.Sprintf("no reachable mongodb server(s) at %s", conf.Conf["mongodb-hosts"]))
		fmt.Fprintln(os.Stderr, "Error: "+e.Error())
		return e
	}
	c.Session = s
	c.DB = c.Session.DB(conf.Conf["mongodb-database"])
	if conf.Conf["mongodb-user"] != "" && conf.Conf["mongodb-password"] != "" {
		c.DB.Login(conf.Conf["mongodb-user"], conf.Conf["mongodb-password"])
	}
	Connection = c
	return
}

func Drop() error {
	return Connection.DB.DropDatabase()
}
<commit_msg>Removed print statement of error message from db.Initialize because this error message should be printed by the code that called db.Initialize().<commit_after>// Package db to connect to mongodb
package db

import (
	"errors"
	"fmt"
	"github.com/MG-RAST/Shock/shock-server/conf"
	"labix.org/v2/mgo"
	"time"
)

const (
	DbTimeout = time.Duration(time.Second * 10)
)

var (
	Connection connection
)

type connection struct {
	dbname   string
	username string
	password string
	Session  *mgo.Session
	DB       *mgo.Database
}

func Initialize() (err error) {
	c := connection{}
	s, err := mgo.DialWithTimeout(conf.Conf["mongodb-hosts"], DbTimeout)
	if err != nil {
		e := errors.New(fmt.Sprintf("no reachable mongodb server(s) at %s", conf.Conf["mongodb-hosts"]))
		return e
	}
	c.Session = s
	c.DB = c.Session.DB(conf.Conf["mongodb-database"])
	if conf.Conf["mongodb-user"] != "" && conf.Conf["mongodb-password"] != "" {
		c.DB.Login(conf.Conf["mongodb-user"], conf.Conf["mongodb-password"])
	}
	Connection = c
	return
}

func Drop() error {
	return Connection.DB.DropDatabase()
}
<|endoftext|>


<commit_before>package torrentfs

import (
	"context"
	netContext "context"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"testing"
	"time"

	"bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/missinggo"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/anacrolix/torrent"
	"github.com/anacrolix/torrent/internal/testutil"
	"github.com/anacrolix/torrent/metainfo"
	"github.com/anacrolix/torrent/storage"
)

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}

func TestTCPAddrString(t *testing.T) {
	l, err := net.Listen("tcp4", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	c, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	ras := c.RemoteAddr().String()
	ta := &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: missinggo.AddrPort(l.Addr()),
	}
	s := ta.String()
	if ras != s {
		t.FailNow()
	}
}

type testLayout struct {
	BaseDir   string
	MountDir  string
	Completed string
	Metainfo  *metainfo.MetaInfo
}

func (tl *testLayout) Destroy() error {
	return os.RemoveAll(tl.BaseDir)
}

func newGreetingLayout() (tl testLayout, err error) {
	tl.BaseDir, err = ioutil.TempDir("", "torrentfs")
	if err != nil {
		return
	}
	tl.Completed = filepath.Join(tl.BaseDir, "completed")
	os.Mkdir(tl.Completed, 0777)
	tl.MountDir = filepath.Join(tl.BaseDir, "mnt")
	os.Mkdir(tl.MountDir, 0777)
	testutil.CreateDummyTorrentData(tl.Completed)
	tl.Metainfo = testutil.GreetingMetaInfo()
	return
}

// Unmount without first killing the FUSE connection while there are FUSE
// operations blocked inside the filesystem code.
func TestUnmountWedged(t *testing.T) {
	layout, err := newGreetingLayout()
	require.NoError(t, err)
	defer func() {
		err := layout.Destroy()
		if err != nil {
			t.Log(err)
		}
	}()
	cfg := torrent.NewDefaultClientConfig()
	cfg.DataDir = filepath.Join(layout.BaseDir, "incomplete")
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.DisableTCP = true
	cfg.DisableUTP = true
	client, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	defer client.Close()
	tt, err := client.AddTorrent(layout.Metainfo)
	require.NoError(t, err)
	fs := New(client)
	fuseConn, err := fuse.Mount(layout.MountDir)
	if err != nil {
		switch err.Error() {
		case "cannot locate OSXFUSE":
			fallthrough
		case "fusermount: exit status 1":
			t.Skip(err)
		}
		t.Fatal(err)
	}
	go func() {
		server := fusefs.New(fuseConn, &fusefs.Config{
			Debug: func(msg interface{}) {
				t.Log(msg)
			},
		})
		server.Serve(fs)
	}()
	<-fuseConn.Ready
	if err := fuseConn.MountError; err != nil {
		t.Fatalf("mount error: %s", err)
	}
	ctx, cancel := context.WithCancel(context.Background())
	// Read the greeting file, though it will never be available. This should
	// "wedge" FUSE, requiring the fs object to be forcibly destroyed. The
	// read call will return with a FS error.
	go func() {
		<-ctx.Done()
		fs.mu.Lock()
		fs.event.Broadcast()
		fs.mu.Unlock()
	}()
	go func() {
		defer cancel()
		_, err := ioutil.ReadFile(filepath.Join(layout.MountDir, tt.Info().Name))
		require.Error(t, err)
	}()

	// Wait until the read has blocked inside the filesystem code.
	fs.mu.Lock()
	for fs.blockedReads != 1 && ctx.Err() == nil {
		fs.event.Wait()
	}
	fs.mu.Unlock()

	fs.Destroy()

	for {
		err = fuse.Unmount(layout.MountDir)
		if err != nil {
			t.Logf("error unmounting: %s", err)
			time.Sleep(time.Millisecond)
		} else {
			break
		}
	}

	err = fuseConn.Close()
	assert.NoError(t, err)
}

func TestDownloadOnDemand(t *testing.T) {
	layout, err := newGreetingLayout()
	require.NoError(t, err)
	defer layout.Destroy()
	cfg := torrent.NewDefaultClientConfig()
	cfg.DataDir = layout.Completed
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.Seed = true
	cfg.ListenHost = torrent.LoopbackListenHost
	seeder, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	defer seeder.Close()
	defer testutil.ExportStatusWriter(seeder, "s")()
	// Just to mix things up, the seeder starts with the data, but the leecher
	// starts with the metainfo.
	seederTorrent, err := seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.HashInfoBytes().HexString()))
	require.NoError(t, err)
	go func() {
		// Wait until we get the metainfo, then check for the data.
		<-seederTorrent.GotInfo()
		seederTorrent.VerifyData()
	}()
	cfg = torrent.NewDefaultClientConfig()
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.DisableTCP = true
	cfg.DefaultStorage = storage.NewMMap(filepath.Join(layout.BaseDir, "download"))
	cfg.ListenHost = torrent.LoopbackListenHost
	leecher, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	testutil.ExportStatusWriter(leecher, "l")
	defer leecher.Close()
	leecherTorrent, err := leecher.AddTorrent(layout.Metainfo)
	require.NoError(t, err)
	leecherTorrent.AddClientPeer(seeder)
	fs := New(leecher)
	defer fs.Destroy()
	root, _ := fs.Root()
	node, _ := root.(fusefs.NodeStringLookuper).Lookup(netContext.Background(), "greeting")
	var attr fuse.Attr
	node.Attr(netContext.Background(), &attr)
	size := attr.Size
	resp := &fuse.ReadResponse{
		Data: make([]byte, size),
	}
	h, err := node.(fusefs.NodeOpener).Open(context.TODO(), nil, nil)
	require.NoError(t, err)
	h.(fusefs.HandleReader).Read(netContext.Background(), &fuse.ReadRequest{
		Size: int(size),
	}, resp)
	assert.EqualValues(t, testutil.GreetingFileContents, resp.Data)
}

func TestIsSubPath(t *testing.T) {
	for _, case_ := range []struct {
		parent, child string
		is            bool
	}{
		{"", "", false},
		{"", "/", true},
		{"", "a", true},
		{"a/b", "a/bc", false},
		{"a/b", "a/b", false},
		{"a/b", "a/b/c", true},
		{"a/b", "a//b", false},
	} {
		assert.Equal(t, case_.is, isSubPath(case_.parent, case_.child))
	}
}
<commit_msg>Missed deferring release of an exported status writer<commit_after>package torrentfs

import (
	"context"
	netContext "context"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"testing"
	"time"

	"bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/missinggo"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/anacrolix/torrent"
	"github.com/anacrolix/torrent/internal/testutil"
	"github.com/anacrolix/torrent/metainfo"
	"github.com/anacrolix/torrent/storage"
)

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}

func TestTCPAddrString(t *testing.T) {
	l, err := net.Listen("tcp4", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	c, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	ras := c.RemoteAddr().String()
	ta := &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: missinggo.AddrPort(l.Addr()),
	}
	s := ta.String()
	if ras != s {
		t.FailNow()
	}
}

type testLayout struct {
	BaseDir   string
	MountDir  string
	Completed string
	Metainfo  *metainfo.MetaInfo
}

func (tl *testLayout) Destroy() error {
	return os.RemoveAll(tl.BaseDir)
}

func newGreetingLayout() (tl testLayout, err error) {
	tl.BaseDir, err = ioutil.TempDir("", "torrentfs")
	if err != nil {
		return
	}
	tl.Completed = filepath.Join(tl.BaseDir, "completed")
	os.Mkdir(tl.Completed, 0777)
	tl.MountDir = filepath.Join(tl.BaseDir, "mnt")
	os.Mkdir(tl.MountDir, 0777)
	testutil.CreateDummyTorrentData(tl.Completed)
	tl.Metainfo = testutil.GreetingMetaInfo()
	return
}

// Unmount without first killing the FUSE connection while there are FUSE
// operations blocked inside the filesystem code.
func TestUnmountWedged(t *testing.T) {
	layout, err := newGreetingLayout()
	require.NoError(t, err)
	defer func() {
		err := layout.Destroy()
		if err != nil {
			t.Log(err)
		}
	}()
	cfg := torrent.NewDefaultClientConfig()
	cfg.DataDir = filepath.Join(layout.BaseDir, "incomplete")
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.DisableTCP = true
	cfg.DisableUTP = true
	client, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	defer client.Close()
	tt, err := client.AddTorrent(layout.Metainfo)
	require.NoError(t, err)
	fs := New(client)
	fuseConn, err := fuse.Mount(layout.MountDir)
	if err != nil {
		switch err.Error() {
		case "cannot locate OSXFUSE":
			fallthrough
		case "fusermount: exit status 1":
			t.Skip(err)
		}
		t.Fatal(err)
	}
	go func() {
		server := fusefs.New(fuseConn, &fusefs.Config{
			Debug: func(msg interface{}) {
				t.Log(msg)
			},
		})
		server.Serve(fs)
	}()
	<-fuseConn.Ready
	if err := fuseConn.MountError; err != nil {
		t.Fatalf("mount error: %s", err)
	}
	ctx, cancel := context.WithCancel(context.Background())
	// Read the greeting file, though it will never be available. This should
	// "wedge" FUSE, requiring the fs object to be forcibly destroyed. The
	// read call will return with a FS error.
	go func() {
		<-ctx.Done()
		fs.mu.Lock()
		fs.event.Broadcast()
		fs.mu.Unlock()
	}()
	go func() {
		defer cancel()
		_, err := ioutil.ReadFile(filepath.Join(layout.MountDir, tt.Info().Name))
		require.Error(t, err)
	}()

	// Wait until the read has blocked inside the filesystem code.
	fs.mu.Lock()
	for fs.blockedReads != 1 && ctx.Err() == nil {
		fs.event.Wait()
	}
	fs.mu.Unlock()

	fs.Destroy()

	for {
		err = fuse.Unmount(layout.MountDir)
		if err != nil {
			t.Logf("error unmounting: %s", err)
			time.Sleep(time.Millisecond)
		} else {
			break
		}
	}

	err = fuseConn.Close()
	assert.NoError(t, err)
}

func TestDownloadOnDemand(t *testing.T) {
	layout, err := newGreetingLayout()
	require.NoError(t, err)
	defer layout.Destroy()
	cfg := torrent.NewDefaultClientConfig()
	cfg.DataDir = layout.Completed
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.Seed = true
	cfg.ListenHost = torrent.LoopbackListenHost
	seeder, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	defer seeder.Close()
	defer testutil.ExportStatusWriter(seeder, "s")()
	// Just to mix things up, the seeder starts with the data, but the leecher
	// starts with the metainfo.
	seederTorrent, err := seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.HashInfoBytes().HexString()))
	require.NoError(t, err)
	go func() {
		// Wait until we get the metainfo, then check for the data.
		<-seederTorrent.GotInfo()
		seederTorrent.VerifyData()
	}()
	cfg = torrent.NewDefaultClientConfig()
	cfg.DisableTrackers = true
	cfg.NoDHT = true
	cfg.DisableTCP = true
	cfg.DefaultStorage = storage.NewMMap(filepath.Join(layout.BaseDir, "download"))
	cfg.ListenHost = torrent.LoopbackListenHost
	leecher, err := torrent.NewClient(cfg)
	require.NoError(t, err)
	testutil.ExportStatusWriter(leecher, "l")()
	defer leecher.Close()
	leecherTorrent, err := leecher.AddTorrent(layout.Metainfo)
	require.NoError(t, err)
	leecherTorrent.AddClientPeer(seeder)
	fs := New(leecher)
	defer fs.Destroy()
	root, _ := fs.Root()
	node, _ := root.(fusefs.NodeStringLookuper).Lookup(netContext.Background(), "greeting")
	var attr fuse.Attr
	node.Attr(netContext.Background(), &attr)
	size := attr.Size
	resp := &fuse.ReadResponse{
		Data: make([]byte, size),
	}
	h, err := node.(fusefs.NodeOpener).Open(context.TODO(), nil, nil)
	require.NoError(t, err)
	h.(fusefs.HandleReader).Read(netContext.Background(), &fuse.ReadRequest{
		Size: int(size),
	}, resp)
	assert.EqualValues(t, testutil.GreetingFileContents, resp.Data)
}

func TestIsSubPath(t *testing.T) {
	for _, case_ := range []struct {
		parent, child string
		is            bool
	}{
		{"", "", false},
		{"", "/", true},
		{"", "a", true},
		{"a/b", "a/bc", false},
		{"a/b", "a/b", false},
		{"a/b", "a/b/c", true},
		{"a/b", "a//b", false},
	} {
		assert.Equal(t, case_.is, isSubPath(case_.parent, case_.child))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"time"
)

var workers int = 5
var resources = []int{0, 0, 0, 0, 0}
var load = []int{0, 0, 0, 0, 0}

var time_interval_request time.Duration = 2.0 * time.Millisecond
var time_interval_work time.Duration = 3.0 * time.Millisecond

func main() {
	for i := 0; i < 10; i++ {
		worker := choose_worker(workers)
		can_work := resources_available(worker)
		if can_work {
			go async_work(worker)
		} else {
			fmt.Println(worker, "- blocked")
		}

		time.Sleep(time_interval_request)
	}
	fmt.Println("done")

	report()
}

func choose_worker(workers int) int {
	worker := rand.Intn(workers)
	return worker
}

func resources_available(worker int) bool {
	left := left(worker)
	right := right(worker)

	if resources[left] == 0 && resources[right] == 0 {
		return true
	} else {
		return false
	}
}

func async_work(worker int) {
	fmt.Println(worker, "+ working")

	left := left(worker)
	right := right(worker)

	// reserve resources
	resources[left] = 1
	resources[right] = 1
	// work
	time.Sleep(time_interval_work)
	// record metrics
	load[worker] += 1
	// put resources back
	resources[left] = 0
	resources[right] = 0
}

func left(i int) int {
	return i
}

func right(i int) int {
	right := i - 1
	if right == -1 {
		right = workers - 1
	}
	return right
}

func report() {
	total_jobs := 0
	for _, worker_jobs := range load {
		total_jobs += worker_jobs
	}

	load_percent := []float64{0, 0, 0, 0, 0}
	for i := 0; i < len(load); i++ {
		total_jobs := float64(total_jobs)
		worker_jobs := float64(load[i])
		worker_percent := worker_jobs / total_jobs

		load_percent[i] = worker_percent
	}

	fmt.Println("total_jobs", total_jobs)
	fmt.Println("job distribution", load_percent)
}
<commit_msg>completed a semi dynamic model - go back and implement PID correction<commit_after>package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

var workers int = 5
var number_of_simulations = 100

var resources = make([]int, workers)
var load = make([]int, workers)

func random_duration() time.Duration {
	r := rand.Float64() * 20.0
	d := time.Duration(r)
	t := d * time.Millisecond
	return t
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	m := new(sync.Mutex)
	c := make(chan int)

	for i := 0; i < number_of_simulations; i++ {
		go check_and_work(c, *m)
		c <- select_worker(workers)
		time.Sleep(random_duration())
	}

	report()
}

func select_worker(workers int) int {
	// TODO
	// weight selection so distribution is not normalized
	worker := rand.Intn(workers)

	// provide Proportional, Integral, and Derivative correction

	return worker
}

func check_and_work(c chan int, m sync.Mutex) {
	worker := <-c

	m.Lock()
	can_work := resources_available(worker)

	if can_work {
		reserve(worker)
		m.Unlock()

		work(worker)

		m.Lock()
		free(worker)
	}

	m.Unlock()
}

func resources_available(worker int) bool {
	left := left(worker)
	right := right(worker)

	if resources[left] == 0 && resources[right] == 0 {
		return true
	} else {
		return false
	}
}

func reserve(worker int) {
	left := left(worker)
	right := right(worker)

	resources[left] = 1
	resources[right] = 1
}

func free(worker int) {
	left := left(worker)
	right := right(worker)

	resources[left] = 0
	resources[right] = 0
}

func work(worker int) {
	time.Sleep(random_duration())
	load[worker] += 1
}

func left(i int) int {
	return i
}

func right(i int) int {
	right := i - 1
	if right == -1 {
		right = workers - 1
	}
	return right
}

func report() {
	total_jobs := 0
	for _, worker_jobs := range load {
		total_jobs += worker_jobs
	}

	load_percent := make([]float64, workers)
	for i := 0; i < len(load); i++ {
		total_jobs := float64(total_jobs)
		worker_jobs := float64(load[i])
		worker_percent := worker_jobs / total_jobs

		load_percent[i] = worker_percent
	}

	fmt.Println("Jobs", number_of_simulations)
	fmt.Println("- block", number_of_simulations-total_jobs)
	fmt.Println("- completed", total_jobs)
	fmt.Println("- distribution", load_percent)
}
<|endoftext|>