<commit_before>package collector

import (
	"encoding/csv"
	"fmt"
	"os"

	"github.com/henrylee2cn/pholcus/common/util"
	"github.com/henrylee2cn/pholcus/config"
	"github.com/henrylee2cn/pholcus/logs"
	"github.com/henrylee2cn/pholcus/runtime/cache"
)

/************************ CSV 输出 ***************************/
func init() {
	DataOutput["csv"] = func(self *Collector) (err error) {
		defer func() {
			if p := recover(); p != nil {
				err = fmt.Errorf("%v", p)
			}
		}()
		var (
			namespace = util.FileNameReplace(self.namespace())
			sheets    = make(map[string]*csv.Writer)
		)
		for _, datacell := range self.dataDocker {
			var subNamespace = util.FileNameReplace(self.subNamespace(datacell))
			if _, ok := sheets[subNamespace]; !ok {
				folder := config.TEXT_DIR + "/" + cache.StartTime.Format("2006-01-02 150405") + "/" + joinNamespaces(namespace, subNamespace)
				filename := fmt.Sprintf("%v/%v-%v.csv", folder, self.sum[0], self.sum[1])

				// 创建/打开目录
				f, err := os.Stat(folder)
				if err != nil || !f.IsDir() {
					if err := os.MkdirAll(folder, 0777); err != nil {
						logs.Log.Error("Error: %v\n", err)
					}
				}

				// 按数据分类创建文件
				file, err := os.Create(filename)

				if err != nil {
					logs.Log.Error("%v", err)
					continue
				}

				file.WriteString("\xEF\xBB\xBF") // 写入UTF-8 BOM

				sheets[subNamespace] = csv.NewWriter(file)
				th := self.MustGetRule(datacell["RuleName"].(string)).ItemFields
				if self.Spider.OutDefaultField() {
					th = append(th, "当前链接", "上级链接", "下载时间")
				}
				sheets[subNamespace].Write(th)

				defer func(file *os.File) {
					// 发送缓存数据流
					sheets[subNamespace].Flush()
					// 关闭文件
					file.Close()
				}(file)
			}

			row := []string{}
			for _, title := range self.MustGetRule(datacell["RuleName"].(string)).ItemFields {
				vd := datacell["Data"].(map[string]interface{})
				if v, ok := vd[title].(string); ok || vd[title] == nil {
					row = append(row, v)
				} else {
					row = append(row, util.JsonString(vd[title]))
				}
			}
			if self.Spider.OutDefaultField() {
				row = append(row, datacell["Url"].(string))
				row = append(row, datacell["ParentUrl"].(string))
				row = append(row, datacell["DownloadTime"].(string))
			}
			sheets[subNamespace].Write(row)
		}
		return
	}
}
<commit_msg>优化defer写法<commit_after>package collector

import (
	"encoding/csv"
	"fmt"
	"os"

	"github.com/henrylee2cn/pholcus/common/util"
	"github.com/henrylee2cn/pholcus/config"
	"github.com/henrylee2cn/pholcus/logs"
	"github.com/henrylee2cn/pholcus/runtime/cache"
)

/************************ CSV 输出 ***************************/
func init() {
	DataOutput["csv"] = func(self *Collector) (err error) {
		defer func() {
			if p := recover(); p != nil {
				err = fmt.Errorf("%v", p)
			}
		}()
		var (
			namespace = util.FileNameReplace(self.namespace())
			sheets    = make(map[string]*csv.Writer)
		)
		for _, datacell := range self.dataDocker {
			var subNamespace = util.FileNameReplace(self.subNamespace(datacell))
			if _, ok := sheets[subNamespace]; !ok {
				folder := config.TEXT_DIR + "/" + cache.StartTime.Format("2006-01-02 150405") + "/" + joinNamespaces(namespace, subNamespace)
				filename := fmt.Sprintf("%v/%v-%v.csv", folder, self.sum[0], self.sum[1])

				// 创建/打开目录
				f, err := os.Stat(folder)
				if err != nil || !f.IsDir() {
					if err := os.MkdirAll(folder, 0777); err != nil {
						logs.Log.Error("Error: %v\n", err)
					}
				}

				// 按数据分类创建文件
				file, err := os.Create(filename)

				if err != nil {
					logs.Log.Error("%v", err)
					continue
				}
				defer func() {
					// 发送缓存数据流
					sheets[subNamespace].Flush()
					// 关闭文件
					file.Close()
				}()

				file.WriteString("\xEF\xBB\xBF") // 写入UTF-8 BOM

				sheets[subNamespace] = csv.NewWriter(file)
				th := self.MustGetRule(datacell["RuleName"].(string)).ItemFields
				if self.Spider.OutDefaultField() {
					th = append(th, "当前链接", "上级链接", "下载时间")
				}
				sheets[subNamespace].Write(th)
			}

			row := []string{}
			for _, title := range self.MustGetRule(datacell["RuleName"].(string)).ItemFields {
				vd := datacell["Data"].(map[string]interface{})
				if v, ok := vd[title].(string); ok || vd[title] == nil {
					row = append(row, v)
				} else {
					row = append(row, util.JsonString(vd[title]))
				}
			}
			if self.Spider.OutDefaultField() {
				row = append(row, datacell["Url"].(string))
				row = append(row, datacell["ParentUrl"].(string))
				row = append(row, datacell["DownloadTime"].(string))
			}
			sheets[subNamespace].Write(row)
		}
		return
	}
}
<|endoftext|>


<commit_before>// On-disk mutex protecting a resource
//
// A lock is represented on disk by a directory of a particular name,
// containing an information file.  Taking a lock is done by renaming a
// temporary directory into place.  We use temporary directories because for
// all filesystems we believe that exactly one attempt to claim the lock will
// succeed and the others will fail.
package fslock

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"time"
)

const nameRegexp = "^[a-z]+[a-z0-9.-]*$"

var (
	ErrLockNotHeld = errors.New("lock not held")

	validName = regexp.MustCompile(nameRegexp)

	lockWaitDelay = 1 * time.Second
)

type Lock struct {
	name   string
	parent string
	nonce  string
}

func generateNonce() (string, error) {
	const size = 20
	var nonce [size]byte
	if _, err := io.ReadFull(rand.Reader, []byte(nonce[0:size])); err != nil {
		return "", err
	}
	return string(nonce[:]), nil
}

// Return a new lock.
func NewLock(lockDir, name string) (*Lock, error) {
	nonce, err := generateNonce()
	if !validName.MatchString(name) {
		return nil, fmt.Errorf("Invalid lock name %q.  Names must match %q", name, nameRegexp)
	}
	if err != nil {
		return nil, err
	}
	lock := &Lock{
		name:   name,
		parent: lockDir,
		nonce:  nonce,
	}
	// Ensure the parent exists.
	dir, err := os.Open(lock.parent)
	if os.IsNotExist(err) {
		// try to make it
		err = os.MkdirAll(lock.parent, 0755)
		// Since we have just created the directory successfully, return now.
		if err == nil {
			return lock, nil
		}
	}
	if err != nil {
		return nil, err
	}
	// Make sure it is actually a directory
	fileInfo, err := dir.Stat()
	if err != nil {
		return nil, err
	}
	if !fileInfo.IsDir() {
		return nil, fmt.Errorf("lock dir %q exists and is a file not a directory", lockDir)
	}
	return lock, nil
}

func (lock *Lock) namedLockDir() string {
	return path.Join(lock.parent, lock.name)
}

func (lock *Lock) heldFile() string {
	return path.Join(lock.namedLockDir(), "held")
}

func (lock *Lock) acquire() (bool, error) {
	// If the namedLockDir exists, then the lock is held by someone else.
	dir, err := os.Open(lock.namedLockDir())
	if err == nil {
		dir.Close()
		return false, nil
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	// Create a temporary directory (in the temp dir), and then move it to the right name.
	tempDirName, err := ioutil.TempDir("", "temp-lock")
	if err != nil {
		return false, err // this shouldn't really fail...
	}
	err = os.Rename(tempDirName, lock.namedLockDir())
	if os.IsExist(err) {
		// Beaten to it, clean up temporary directory.
		os.RemoveAll(tempDirName)
		return false, nil
	} else if err != nil {
		return false, err
	}
	// write nonce
	err = ioutil.WriteFile(lock.heldFile(), []byte(lock.nonce), 0755)
	if err != nil {
		return false, err
	}
	// We now have the lock.
	return true, nil
}

// Lock blocks until it is able to acquire the lock.
func (lock *Lock) Lock() error {
	for {
		acquired, err := lock.acquire()
		if err != nil {
			return err
		}
		if acquired {
			return nil
		}
		time.Sleep(lockWaitDelay)
	}
	panic("unreachable")
	return nil // unreachable
}

func (lock *Lock) TryLock(duration time.Duration) (isLocked bool, err error) {
	locked := make(chan bool)
	error := make(chan error)
	timeout := make(chan struct{})
	defer func() {
		close(locked)
		close(error)
		close(timeout)
	}()

	go func() {
		for {
			acquired, err := lock.acquire()
			if err != nil {
				locked <- false
				error <- err
				return
			}
			if acquired {
				locked <- true
				error <- nil
				return
			}
			select {
			case <-timeout:
				locked <- false
				error <- nil
				return
			case <-time.After(lockWaitDelay):
				// Keep trying...
			}
		}
	}()

	select {
	case isLocked = <-locked:
		err = <-error
		return
	case <-time.After(duration):
		timeout <- struct{}{}
	}
	// It is possible that the timeout got signalled just before the goroutine
	// tried again, so check the results rather than automatically failing.
	return <-locked, <-error
}

// IsLockHeld returns true if and only if the namedLockDir exists, and the
// file 'held' in that directory contains the nonce for this lock.
func (lock *Lock) IsLockHeld() bool {
	heldNonce, err := ioutil.ReadFile(lock.heldFile())
	if err != nil {
		return false
	}
	return string(heldNonce) == lock.nonce
}

func (lock *Lock) Unlock() error {
	if !lock.IsLockHeld() {
		return ErrLockNotHeld
	}
	return os.RemoveAll(lock.namedLockDir())
}
<commit_msg>Keep the nonce as a byte slice, and new comments.<commit_after>// On-disk mutex protecting a resource
//
// A lock is represented on disk by a directory of a particular name,
// containing an information file.  Taking a lock is done by renaming a
// temporary directory into place.  We use temporary directories because for
// all filesystems we believe that exactly one attempt to claim the lock will
// succeed and the others will fail.
package fslock

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"time"
)

const nameRegexp = "^[a-z]+[a-z0-9.-]*$"

var (
	ErrLockNotHeld = errors.New("lock not held")

	validName = regexp.MustCompile(nameRegexp)

	lockWaitDelay = 1 * time.Second
)

type Lock struct {
	name   string
	parent string
	nonce  []byte
}

func generateNonce() ([]byte, error) {
	nonce := make([]byte, 20)
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return nil, err
	}
	return nonce, nil
}

// NewLock returns a new lock with the given name within the given lock
// directory, without acquiring it. The lock name must match the regular
// expression `^[a-z]+[a-z0-9.-]*`.
func NewLock(lockDir, name string) (*Lock, error) {
	nonce, err := generateNonce()
	if err != nil {
		return nil, err
	}
	if !validName.MatchString(name) {
		return nil, fmt.Errorf("Invalid lock name %q.  Names must match %q", name, nameRegexp)
	}
	if err != nil {
		return nil, err
	}
	lock := &Lock{
		name:   name,
		parent: lockDir,
		nonce:  nonce,
	}
	// Ensure the parent exists.
	dir, err := os.Open(lock.parent)
	if os.IsNotExist(err) {
		// try to make it
		err = os.MkdirAll(lock.parent, 0755)
		// Since we have just created the directory successfully, return now.
		if err == nil {
			return lock, nil
		}
	}
	if err != nil {
		return nil, err
	}
	// Make sure it is actually a directory
	fileInfo, err := dir.Stat()
	if err != nil {
		return nil, err
	}
	if !fileInfo.IsDir() {
		return nil, fmt.Errorf("lock dir %q exists and is a file not a directory", lockDir)
	}
	return lock, nil
}

func (lock *Lock) namedLockDir() string {
	return path.Join(lock.parent, lock.name)
}

func (lock *Lock) heldFile() string {
	return path.Join(lock.namedLockDir(), "held")
}

func (lock *Lock) acquire() (bool, error) {
	// If the namedLockDir exists, then the lock is held by someone else.
	dir, err := os.Open(lock.namedLockDir())
	if err == nil {
		dir.Close()
		return false, nil
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	// Create a temporary directory (in the temp dir), and then move it to the right name.
	tempDirName, err := ioutil.TempDir("", "temp-lock")
	if err != nil {
		return false, err // this shouldn't really fail...
	}
	err = os.Rename(tempDirName, lock.namedLockDir())
	if os.IsExist(err) {
		// Beaten to it, clean up temporary directory.
		os.RemoveAll(tempDirName)
		return false, nil
	} else if err != nil {
		return false, err
	}
	// write nonce
	err = ioutil.WriteFile(lock.heldFile(), []byte(lock.nonce), 0755)
	if err != nil {
		return false, err
	}
	// We now have the lock.
	return true, nil
}

// Lock blocks until it is able to acquire the lock.
func (lock *Lock) Lock() error {
	for {
		acquired, err := lock.acquire()
		if err != nil {
			return err
		}
		if acquired {
			return nil
		}
		time.Sleep(lockWaitDelay)
	}
	panic("unreachable")
	return nil // unreachable
}

func (lock *Lock) TryLock(duration time.Duration) (isLocked bool, err error) {
	locked := make(chan bool)
	error := make(chan error)
	timeout := make(chan struct{})
	defer func() {
		close(locked)
		close(error)
		close(timeout)
	}()

	go func() {
		for {
			acquired, err := lock.acquire()
			if err != nil {
				locked <- false
				error <- err
				return
			}
			if acquired {
				locked <- true
				error <- nil
				return
			}
			select {
			case <-timeout:
				locked <- false
				error <- nil
				return
			case <-time.After(lockWaitDelay):
				// Keep trying...
			}
		}
	}()

	select {
	case isLocked = <-locked:
		err = <-error
		return
	case <-time.After(duration):
		timeout <- struct{}{}
	}
	// It is possible that the timeout got signalled just before the goroutine
	// tried again, so check the results rather than automatically failing.
	return <-locked, <-error
}

// IsLockHeld returns true if and only if the namedLockDir exists, and the
// file 'held' in that directory contains the nonce for this lock.
func (lock *Lock) IsLockHeld() bool {
	heldNonce, err := ioutil.ReadFile(lock.heldFile())
	if err != nil {
		return false
	}
	return string(heldNonce) == lock.nonce
}

func (lock *Lock) Unlock() error {
	if !lock.IsLockHeld() {
		return ErrLockNotHeld
	}
	return os.RemoveAll(lock.namedLockDir())
}
<|endoftext|>


<commit_before>// Glide is a command line utility that manages Go project dependencies and
// your GOPATH.
//
// Dependencies are managed via a glide.yaml in the root of a project. The yaml
// file lets you specify projects, versions (tags, branches, or references),
// and even alias one location in as other one. Aliasing is useful when supporting
// forks without needing to rewrite the imports in a codebase.
//
// A glide.yaml file looks like:
//
// 		package: github.com/Masterminds/glide
// 		imports:
//			- package: github.com/Masterminds/cookoo
//			  vcs: git
//			  ref: 1.1.0
//			  subpackages: **
//			- package: github.com/kylelemons/go-gypsy
//			  subpackages: yaml
//
// Glide puts dependencies in a _vendor directory. Go utilities require this to
// be in your GOPATH. Glide makes this easy. Use the `glide in` command to enter
// a shell (your default) with the GOPATH set to the projects _vendor directory.
// To leave this shell simply exit it.
//
// If your .bashrc, .zshrc, or other startup shell sets your GOPATH you many need
// to optionally set it using something like:
//
//		if [ "" = "${GOPATH}" ]; then
//		  export GOPATH="/some/dir"
//		fi
//
// For more information use the `glide help` command or see https://github.com/Masterminds/glide
package main

import (
	"github.com/Masterminds/glide/cmd"

	"github.com/Masterminds/cookoo"
	"github.com/codegangsta/cli"

	"os"
)

var version string = "0.2.0-dev"

const Summary = "Manage Go projects with ease."
const Usage = `Manage dependencies, naming, and GOPATH for your Go projects.

Each project should have a 'glide.yaml' file in the project directory. Files
look something like this:

	package: github.com/Masterminds/glide
	imports:
		- package: github.com/Masterminds/cookoo
		  vcs: git
		  ref: 1.1.0
		  subpackages: **
  		- package: github.com/kylelemons/go-gypsy
		  subpackages: yaml
`

func main() {
	reg, router, cxt := cookoo.Cookoo()

	routes(reg, cxt)

	app := cli.NewApp()
	app.Name = "glide"
	app.Usage = Usage
	app.Version = version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "yaml, y",
			Value: "glide.yaml",
			Usage: "Set a YAML configuration file.",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "Quiet (no info or debug messages)",
		},
	}

	app.Commands = commands(cxt, router)

	app.Run(os.Args)
}

func commands(cxt cookoo.Context, router *cookoo.Router) []cli.Command {
	return []cli.Command{
		{
			Name:      "create",
			ShortName: "init",
			Usage:     "Initialize a new project, creating a template glide.yaml",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("create", cxt, false)
			},
		},
		{
			Name:  "in",
			Usage: "Glide into a commandline shell preconfigured for your project",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("in", cxt, false)
			},
		},
		{
			Name:  "install",
			Usage: "Install all packages in the glide.yaml",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("install", cxt, false)
			},
		},
		{
			Name:  "into",
			Usage: "The same as running \"cd /my/project && glide in\"",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				cxt.Put("toPath", c.Args()[0])
				router.HandleRequest("into", cxt, false)
			},
		},
		{
			Name:  "godeps",
			Usage: "Import Godeps and Godeps-Git files and display the would-be yaml file",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("godeps", cxt, false)
			},
		},
		{
			Name:  "gopath",
			Usage: "Display the GOPATH for the present project",
			Description: `Emits the GOPATH for the current project. Useful for
   things like manually setting GOPATH: GOPATH=$(glide gopath)`,
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("gopath", cxt, false)
			},
		},
		{
			Name:  "pin",
			Usage: "Print a YAML file with all of the packages pinned to the current version",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("pin", cxt, false)
			},
		},
		{
			Name:  "rebuild",
			Usage: "Rebuild ('go build') the dependencies",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("rebuild", cxt, false)
			},
		},
		{
			Name:      "status",
			ShortName: "s",
			Usage:     "Display a status report",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("status", cxt, false)
			},
		},
		{
			Name:      "update",
			ShortName: "up",
			Usage:     "Update existing packages",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("update", cxt, false)
			},
		},
	}
}

func routes(reg *cookoo.Registry, cxt cookoo.Context) {

	reg.Route("@startup", "Parse args and send to the right subcommand.").
		// TODO: Add setup for debug in addition to quiet.
		Does(cmd.BeQuiet, "quiet").
		Using("quiet").From("cxt:q")

	reg.Route("@ready", "Prepare for glide commands.").
		Does(cmd.ReadyToGlide, "ready").
		Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml")

	reg.Route("into", "Creates a new Glide shell.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Does(cmd.Into, "in").Using("into").From("cxt:toPath").
		Using("into").WithDefault("").From("cxt:toPath").
		Includes("@ready")

	reg.Route("in", "Set GOPATH and supporting env vars.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Includes("@ready").
		Does(cmd.Into, "in").
		Using("into").WithDefault("").From("cxt:toPath").
		Using("conf").From("cxt:cfg")

	reg.Route("gopath", "Return the GOPATH for the present project.").
		Includes("@startup").
		Does(cmd.In, "gopath")

	reg.Route("out", "Set GOPATH back to former val.").
		Does(cmd.Out, "gopath")

	reg.Route("install", "Install dependencies.").
		Includes("@startup").
		Does(cmd.InGopath, "pathIsRight").
		Includes("@ready").
		Does(cmd.Mkdir, "dir").Using("dir").WithDefault("_vendor").
		Does(cmd.LinkPackage, "alias").
		Does(cmd.GetImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("update", "Update dependencies.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.UpdateImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("rebuild", "Rebuild dependencies").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("pin", "Print a YAML file with all of the packages pinned to the current version.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("godeps", "Read a Godeps file").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.Godeps, "godeps").
		Does(cmd.AddDependencies, "addGodeps").
		Using("dependencies").From("cxt:godeps").
		Using("conf").From("cxt:cfg").
		Does(cmd.GodepsGit, "godepsGit").
		Does(cmd.AddDependencies, "addGodepsGit").
		Using("dependencies").From("cxt:godepsGit").
		Using("conf").From("cxt:cfg").
		// Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("create", "Initialize Glide").
		Includes("@startup").
		Does(cmd.InitGlide, "init")

	reg.Route("status", "Status").
		Includes("@startup").
		Does(cmd.Status, "status")

	reg.Route("@plugin", "Try to send to a plugin.").
		Includes("@ready").
		Does(cmd.DropToShell, "plugin")
}
<commit_msg>Commenting out the Out command as you need to 'exit' the shell.<commit_after>// Glide is a command line utility that manages Go project dependencies and
// your GOPATH.
//
// Dependencies are managed via a glide.yaml in the root of a project. The yaml
// file lets you specify projects, versions (tags, branches, or references),
// and even alias one location in as other one. Aliasing is useful when supporting
// forks without needing to rewrite the imports in a codebase.
//
// A glide.yaml file looks like:
//
// 		package: github.com/Masterminds/glide
// 		imports:
//			- package: github.com/Masterminds/cookoo
//			  vcs: git
//			  ref: 1.1.0
//			  subpackages: **
//			- package: github.com/kylelemons/go-gypsy
//			  subpackages: yaml
//
// Glide puts dependencies in a _vendor directory. Go utilities require this to
// be in your GOPATH. Glide makes this easy. Use the `glide in` command to enter
// a shell (your default) with the GOPATH set to the projects _vendor directory.
// To leave this shell simply exit it.
//
// If your .bashrc, .zshrc, or other startup shell sets your GOPATH you many need
// to optionally set it using something like:
//
//		if [ "" = "${GOPATH}" ]; then
//		  export GOPATH="/some/dir"
//		fi
//
// For more information use the `glide help` command or see https://github.com/Masterminds/glide
package main

import (
	"github.com/Masterminds/glide/cmd"

	"github.com/Masterminds/cookoo"
	"github.com/codegangsta/cli"

	"os"
)

var version string = "0.2.0-dev"

const Summary = "Manage Go projects with ease."
const Usage = `Manage dependencies, naming, and GOPATH for your Go projects.

Each project should have a 'glide.yaml' file in the project directory. Files
look something like this:

	package: github.com/Masterminds/glide
	imports:
		- package: github.com/Masterminds/cookoo
		  vcs: git
		  ref: 1.1.0
		  subpackages: **
  		- package: github.com/kylelemons/go-gypsy
		  subpackages: yaml
`

func main() {
	reg, router, cxt := cookoo.Cookoo()

	routes(reg, cxt)

	app := cli.NewApp()
	app.Name = "glide"
	app.Usage = Usage
	app.Version = version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "yaml, y",
			Value: "glide.yaml",
			Usage: "Set a YAML configuration file.",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "Quiet (no info or debug messages)",
		},
	}

	app.Commands = commands(cxt, router)

	app.Run(os.Args)
}

func commands(cxt cookoo.Context, router *cookoo.Router) []cli.Command {
	return []cli.Command{
		{
			Name:      "create",
			ShortName: "init",
			Usage:     "Initialize a new project, creating a template glide.yaml",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("create", cxt, false)
			},
		},
		{
			Name:  "in",
			Usage: "Glide into a commandline shell preconfigured for your project",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("in", cxt, false)
			},
		},
		{
			Name:  "install",
			Usage: "Install all packages in the glide.yaml",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("install", cxt, false)
			},
		},
		{
			Name:  "into",
			Usage: "The same as running \"cd /my/project && glide in\"",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				cxt.Put("toPath", c.Args()[0])
				router.HandleRequest("into", cxt, false)
			},
		},
		{
			Name:  "godeps",
			Usage: "Import Godeps and Godeps-Git files and display the would-be yaml file",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("godeps", cxt, false)
			},
		},
		{
			Name:  "gopath",
			Usage: "Display the GOPATH for the present project",
			Description: `Emits the GOPATH for the current project. Useful for
   things like manually setting GOPATH: GOPATH=$(glide gopath)`,
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("gopath", cxt, false)
			},
		},
		{
			Name:  "pin",
			Usage: "Print a YAML file with all of the packages pinned to the current version",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("pin", cxt, false)
			},
		},
		{
			Name:  "rebuild",
			Usage: "Rebuild ('go build') the dependencies",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("rebuild", cxt, false)
			},
		},
		{
			Name:      "status",
			ShortName: "s",
			Usage:     "Display a status report",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("status", cxt, false)
			},
		},
		{
			Name:      "update",
			ShortName: "up",
			Usage:     "Update existing packages",
			Action: func(c *cli.Context) {
				cxt.Put("q", c.GlobalBool("quiet"))
				cxt.Put("yaml", c.GlobalString("yaml"))
				router.HandleRequest("update", cxt, false)
			},
		},
	}
}

func routes(reg *cookoo.Registry, cxt cookoo.Context) {

	reg.Route("@startup", "Parse args and send to the right subcommand.").
		// TODO: Add setup for debug in addition to quiet.
		Does(cmd.BeQuiet, "quiet").
		Using("quiet").From("cxt:q")

	reg.Route("@ready", "Prepare for glide commands.").
		Does(cmd.ReadyToGlide, "ready").
		Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml")

	reg.Route("into", "Creates a new Glide shell.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Does(cmd.Into, "in").Using("into").From("cxt:toPath").
		Using("into").WithDefault("").From("cxt:toPath").
		Includes("@ready")

	reg.Route("in", "Set GOPATH and supporting env vars.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Includes("@ready").
		Does(cmd.Into, "in").
		Using("into").WithDefault("").From("cxt:toPath").
		Using("conf").From("cxt:cfg")

	reg.Route("gopath", "Return the GOPATH for the present project.").
		Includes("@startup").
		Does(cmd.In, "gopath")

	// reg.Route("out", "Set GOPATH back to former val.").
	// 	Does(cmd.Out, "gopath")

	reg.Route("install", "Install dependencies.").
		Includes("@startup").
		Does(cmd.InGopath, "pathIsRight").
		Includes("@ready").
		Does(cmd.Mkdir, "dir").Using("dir").WithDefault("_vendor").
		Does(cmd.LinkPackage, "alias").
		Does(cmd.GetImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("update", "Update dependencies.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.UpdateImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("rebuild", "Rebuild dependencies").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("pin", "Print a YAML file with all of the packages pinned to the current version.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("godeps", "Read a Godeps file").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.Godeps, "godeps").
		Does(cmd.AddDependencies, "addGodeps").
		Using("dependencies").From("cxt:godeps").
		Using("conf").From("cxt:cfg").
		Does(cmd.GodepsGit, "godepsGit").
		Does(cmd.AddDependencies, "addGodepsGit").
		Using("dependencies").From("cxt:godepsGit").
		Using("conf").From("cxt:cfg").
		// Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("create", "Initialize Glide").
		Includes("@startup").
		Does(cmd.InitGlide, "init")

	reg.Route("status", "Status").
		Includes("@startup").
		Does(cmd.Status, "status")

	reg.Route("@plugin", "Try to send to a plugin.").
		Includes("@ready").
		Does(cmd.DropToShell, "plugin")
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"math"
	"math/rand"
	"sync"
)

const (
	a float64 = 3.0
	b float64 = 10.0
	c float64 = 0.5
)

type drinkData interface {
	//Gets count of drinks containing this base ingredient
	NumDrinksWithIngredient(ingredientID int) int
	//Gets count of drinks containing first and second base ingredients
	NumDrinksWithBothIngredients(firstID int, secondID int) int
	//Gets count of drinks containing first, second, and third base ingredients
	NumDrinksWithThreeIngredients(firstID int, secondID int, thirdID int) int
	NumIngredientsInDrink(ingredientID int) (int, int)
}

type drinkCreator struct {
	data      drinkData
	nameMaker nameGenerator
}

func (c *drinkCreator) utilityOfIngredient(candidateID int, currentIncludedIds []int) (float64, error) {
	if len(currentIncludedIds) == 0 {
		return 0, errors.New("Tried to calculate utility without any ingredients already included")
	}

	inCommonWithLast := c.data.NumDrinksWithBothIngredients(candidateID, currentIncludedIds[len(currentIncludedIds)-1])

	totalWithLast := c.data.NumDrinksWithIngredient(currentIncludedIds[len(currentIncludedIds)-1])

	if len(currentIncludedIds) < 2 {
		return utility(inCommonWithLast, totalWithLast, 0, 0), nil
	}

	inCommonWithLastTwo := c.data.NumDrinksWithThreeIngredients(
		candidateID,
		currentIncludedIds[len(currentIncludedIds)-1],
		currentIncludedIds[len(currentIncludedIds)-2])
	totalWithLastTwo := c.data.NumDrinksWithBothIngredients(
		currentIncludedIds[len(currentIncludedIds)-1],
		currentIncludedIds[len(currentIncludedIds)-2])
	return utility(inCommonWithLast, totalWithLast, inCommonWithLastTwo, totalWithLastTwo), nil
}

func (c *drinkCreator) utilityOfAllCandidates(candidateIDs []int, currentlyIncludedIds []int) []float64 {
	var wg sync.WaitGroup
	wg.Add(len(candidateIDs))
	utilities := make([]float64, len(candidateIDs))
	for i, v := range candidateIDs {
		go func(i int, val int) {
			defer wg.Done()
			var err error
			utilities[i], err = c.utilityOfIngredient(val, currentlyIncludedIds)
			if err != nil {
				log.Fatal(err)
			}
		}(i, v)
	}
	wg.Wait()
	return utilities
}

func continueDrawing(utilities []float64) bool {
	firstVal := utilities[0]
	for _, v := range utilities {
		if v != firstVal {
			return true
		}
	}
	draw := rand.Float64()
	if draw < 0.5 {
		return false
	}
	return true
}

func (c *drinkCreator) drawNextIngredient(candidateIDs []int, currentlyIncludedIDs []int) int {
	utilities := c.utilityOfAllCandidates(candidateIDs, currentlyIncludedIDs)
	if continueDrawing(utilities) {
		sum := 0.0
		for _, v := range utilities {
			sum += v
		}
		probabilities := make([]float64, len(utilities))
		cumulative := 0.0
		for i := range probabilities {
			cumulative += utilities[i] / sum
			probabilities[i] = cumulative
		}
		draw := rand.Float64()
		for i, v := range probabilities {
			if draw < v {
				return candidateIDs[i]
			}
		}
	}
	return -1
}

func (c *drinkCreator) makeIngredientList(candidateBaseIDs []int, firstIngredient int) []int {
	averageNumIngredients, maxNumIngredients := c.data.NumIngredientsInDrink(firstIngredient)
	if maxNumIngredients == 0 {
		//If ingredient has no drinks in database make an arbitrary cocktail
		averageNumIngredients = 4
		maxNumIngredients = 6
	}
	numIngredients := numIngredients(averageNumIngredients, maxNumIngredients)
	ingList := []int{firstIngredient}
	for i := 0; i < numIngredients; i++ {
		if len(candidateBaseIDs) == 0 {
			return ingList
		}
		nextIngredient := c.drawNextIngredient(candidateBaseIDs, ingList)
		if nextIngredient == -1 {
			return ingList
		}
		ingList = append(ingList, nextIngredient)
		for i, v := range candidateBaseIDs {
			if v == nextIngredient {
				candidateBaseIDs[i] = candidateBaseIDs[len(candidateBaseIDs)-1]
				candidateBaseIDs = candidateBaseIDs[:len(candidateBaseIDs)-1]
				break
			}
		}
	}
	return ingList
}

func (c *drinkCreator) makeDrink(ingredients []Ingredient) Drink {
	//Get unique base ids
	baseSet := make(map[int]struct{})
	for _, v := range ingredients {
		baseSet[v.BaseID] = struct{}{}
	}
	baseIDs := make([]int, len(baseSet))
	i := 0
	for k := range baseSet {
		baseIDs[i] = k
		i++
	}
	firstIngredient := drawAlcohol(ingredients)
	for i, v := range baseIDs {
		if v == firstIngredient.BaseID {
			baseIDs[i] = baseIDs[len(baseIDs)-1]
			baseIDs = baseIDs[:len(baseIDs)-1]
		}
	}
	ingredientBaseIDs := c.makeIngredientList(baseIDs, firstIngredient.BaseID)
	finalIngredients := make([]Ingredient, 0)
	for _, v := range ingredients {
		if baseIDIncluded(ingredientBaseIDs, v.BaseID) {
			finalIngredients = append(finalIngredients, v)
		}
	}
	return Drink{
		Name:     c.nameMaker.NameWithIngredients(getIds(finalIngredients)),
		Contents: uniform(finalIngredients),
		Size:     Buttchug,
	}
}

func getIds(ingredients []Ingredient) []int {
	ids := make([]int, 0)
	for _, v := range ingredients {
		ids = append(ids, v.BaseID)
	}
	return ids
}

func baseIDIncluded(ids []int, baseID int) bool {
	for _, v := range ids {
		if v == baseID {
			return true
		}
	}
	return false
}

func drawAlcohol(ingredients []Ingredient) Ingredient {
	alcohols := getAlcohols(ingredients)
	return alcohols[rand.Intn(len(alcohols))]
}

func getAlcohols(ingredients []Ingredient) []Ingredient {
	result := make([]Ingredient, 0)
	for _, v := range ingredients {
		if v.Cat == Alcohol {
			result = append(result, v)
		}
	}
	return result
}

//Draws a rounded value from a triangular distribution between 1 and the max
//With the average as the mode
func numIngredients(averageNumIngredients, maxNumIngredients int) int {
	min := 1.0
	max := float64(maxNumIngredients)
	mode := float64(averageNumIngredients)

	f := (c - a) / (b - a)
	draw := rand.Float64()
	if draw < f {
		return int(min + math.Sqrt(draw*(max-min)*(mode-min)) + 0.5)
	}
	return int(max - math.Sqrt((1-draw)*(max-min)*(max-mode)) + 0.5)
}

func utility(inCommonWithLast, totalWithLast, inCommonWithLastTwo, totalWithLastTwo int) float64 {
	if totalWithLast == 0 {
		return 0
	} else if totalWithLastTwo == 0 {
		return a*(float64(inCommonWithLast)/float64(totalWithLast)) + c
	} else {
		return a*(float64(inCommonWithLast)/float64(totalWithLast)) +
			b*(float64(inCommonWithLastTwo)/float64(totalWithLastTwo)) + c
	}
}
<commit_msg>fixed error in triangular distribution where I was using the utility weights accidentally<commit_after>package main

import (
	"errors"
	"log"
	"math"
	"math/rand"
	"sync"
)

type drinkData interface {
	//Gets count of drinks containing this base ingredient
	NumDrinksWithIngredient(ingredientID int) int
	//Gets count of drinks containing first and second base ingredients
	NumDrinksWithBothIngredients(firstID int, secondID int) int
	//Gets count of drinks containing first, second, and third base ingredients
	NumDrinksWithThreeIngredients(firstID int, secondID int, thirdID int) int
	NumIngredientsInDrink(ingredientID int) (int, int)
}

type drinkCreator struct {
	data      drinkData
	nameMaker nameGenerator
}

func (c *drinkCreator) utilityOfIngredient(candidateID int, currentIncludedIds []int) (float64, error) {
	if len(currentIncludedIds) == 0 {
		return 0, errors.New("Tried to calculate utility without any ingredients already included")
	}

	inCommonWithLast := c.data.NumDrinksWithBothIngredients(candidateID, currentIncludedIds[len(currentIncludedIds)-1])

	totalWithLast := c.data.NumDrinksWithIngredient(currentIncludedIds[len(currentIncludedIds)-1])

	if len(currentIncludedIds) < 2 {
		return utility(inCommonWithLast, totalWithLast, 0, 0), nil
	}

	inCommonWithLastTwo := c.data.NumDrinksWithThreeIngredients(
		candidateID,
		currentIncludedIds[len(currentIncludedIds)-1],
		currentIncludedIds[len(currentIncludedIds)-2])
	totalWithLastTwo := c.data.NumDrinksWithBothIngredients(
		currentIncludedIds[len(currentIncludedIds)-1],
		currentIncludedIds[len(currentIncludedIds)-2])
	return utility(inCommonWithLast, totalWithLast, inCommonWithLastTwo, totalWithLastTwo), nil
}

func (c *drinkCreator) utilityOfAllCandidates(candidateIDs []int, currentlyIncludedIds []int) []float64 {
	var wg sync.WaitGroup
	wg.Add(len(candidateIDs))
	utilities := make([]float64, len(candidateIDs))
	for i, v := range candidateIDs {
		go func(i int, val int) {
			defer wg.Done()
			var err error
			utilities[i], err = c.utilityOfIngredient(val, currentlyIncludedIds)
			if err != nil {
				log.Fatal(err)
			}
		}(i, v)
	}
	wg.Wait()
	return utilities
}

func continueDrawing(utilities []float64) bool {
	firstVal := utilities[0]
	for _, v := range utilities {
		if v != firstVal {
			return true
		}
	}
	draw := rand.Float64()
	if draw < 0.5 {
		return false
	}
	return true
}

func (c *drinkCreator) drawNextIngredient(candidateIDs []int, currentlyIncludedIDs []int) int {
	utilities := c.utilityOfAllCandidates(candidateIDs, currentlyIncludedIDs)
	if continueDrawing(utilities) {
		sum := 0.0
		for _, v := range utilities {
			sum += v
		}
		probabilities := make([]float64, len(utilities))
		cumulative := 0.0
		for i := range probabilities {
			cumulative += utilities[i] / sum
			probabilities[i] = cumulative
		}
		draw := rand.Float64()
		for i, v := range probabilities {
			if draw < v {
				return candidateIDs[i]
			}
		}
	}
	return -1
}

func (c *drinkCreator) makeIngredientList(candidateBaseIDs []int, firstIngredient int) []int {
	averageNumIngredients, maxNumIngredients := c.data.NumIngredientsInDrink(firstIngredient)
	if maxNumIngredients == 0 {
		//If ingredient has no drinks in database make an arbitrary cocktail
		averageNumIngredients = 4
		maxNumIngredients = 6
	}
	numIngredients := numIngredients(averageNumIngredients, maxNumIngredients)
	ingList := []int{firstIngredient}
	for i := 0; i < numIngredients; i++ {
		if len(candidateBaseIDs) == 0 {
			return ingList
		}
		nextIngredient := c.drawNextIngredient(candidateBaseIDs, ingList)
		if nextIngredient == -1 {
			return ingList
		}
		ingList = append(ingList, nextIngredient)
		for i, v := range candidateBaseIDs {
			if v == nextIngredient {
				candidateBaseIDs[i] = candidateBaseIDs[len(candidateBaseIDs)-1]
				candidateBaseIDs = candidateBaseIDs[:len(candidateBaseIDs)-1]
				break
			}
		}
	}
	return ingList
}

func (c *drinkCreator) makeDrink(ingredients []Ingredient) Drink {
	//Get unique base ids
	baseSet := make(map[int]struct{})
	for _, v := range ingredients {
		baseSet[v.BaseID] = struct{}{}
	}
	baseIDs := make([]int, len(baseSet))
	i := 0
	for k := range baseSet {
		baseIDs[i] = k
		i++
	}
	firstIngredient := drawAlcohol(ingredients)
	for i, v := range baseIDs {
		if v == firstIngredient.BaseID {
			baseIDs[i] = baseIDs[len(baseIDs)-1]
			baseIDs = baseIDs[:len(baseIDs)-1]
		}
	}
	ingredientBaseIDs := c.makeIngredientList(baseIDs, firstIngredient.BaseID)
	finalIngredients := make([]Ingredient, 0)
	for _, v := range ingredients {
		if baseIDIncluded(ingredientBaseIDs, v.BaseID) {
			finalIngredients = append(finalIngredients, v)
		}
	}
	return Drink{
		Name:     c.nameMaker.NameWithIngredients(getIds(finalIngredients)),
		Contents: uniform(finalIngredients),
		Size:     Buttchug,
	}
}

func getIds(ingredients []Ingredient) []int {
	ids := make([]int, 0)
	for _, v := range ingredients {
		ids = append(ids, v.BaseID)
	}
	return ids
}

func baseIDIncluded(ids []int, baseID int) bool {
	for _, v := range ids {
		if v == baseID {
			return true
		}
	}
	return false
}

func drawAlcohol(ingredients []Ingredient) Ingredient {
	alcohols := getAlcohols(ingredients)
	return alcohols[rand.Intn(len(alcohols))]
}

func getAlcohols(ingredients []Ingredient) []Ingredient {
	result := make([]Ingredient, 0)
	for _, v := range ingredients {
		if v.Cat == Alcohol {
			result = append(result, v)
		}
	}
	return result
}

//Draws a rounded value from a triangular distribution between 1 and the max
//With the average as the mode
func numIngredients(averageNumIngredients, maxNumIngredients int) int {
	min := 1.0
	max := float64(maxNumIngredients)
	mode := float64(averageNumIngredients)

	f := (mode - min) / (max - min)
	draw := rand.Float64()
	if draw < f {
		return int(min + math.Sqrt(draw*(max-min)*(mode-min)) + 0.5)
	}
	return int(max - math.Sqrt((1-draw)*(max-min)*(max-mode)) + 0.5)
}

func utility(inCommonWithLast, totalWithLast, inCommonWithLastTwo, totalWithLastTwo int) float64 {
	const (
		a float64 = 3.0
		b float64 = 10.0
		c float64 = 0.5
	)

	if totalWithLast == 0 {
		return 0
	} else if totalWithLastTwo == 0 {
		return a*(float64(inCommonWithLast)/float64(totalWithLast)) + c
	} else {
		return a*(float64(inCommonWithLast)/float64(totalWithLast)) +
			b*(float64(inCommonWithLastTwo)/float64(totalWithLastTwo)) + c
	}
}
<|endoftext|>


<commit_before>//Implemanta Respuesta para Freeswitch Outbound e Inbound
//La idea inicial, es hacer un clon de plivoframework sencillo
//pero la diferencia es que recibe todo el mensaje o IVR
//y lo ejecuta
package glivo

import (
	"net"
	"net/textproto"
	"bufio"
	"strings"
	"io"
	"io/ioutil"
	"strconv"
	"log"
)

//Una session representa un puerto escuchando peticiones de freeswitch
type Session struct {
	listener *net.Listener
	done chan bool
	logger *log.Logger
}

func NewSession(srv *net.Listener, logger *log.Logger) *Session {
	return &Session{srv,  make(chan bool), logger}
}

func (session *Session) Start(handler func(call *Call)) {

	go func(session *Session){
		calls_active := make([]*Call, 100, 254)
		for {
			select{
			case <-session.done:
				session.logger.Print("Closing server")
				return;
			default:
			}

			conn, err := (*session.listener).Accept()
			if err != nil {
				continue
			}

			conn.Write([]byte("connect\n\n"))
			buf := bufio.NewReaderSize(conn, 4096)
			reader := textproto.NewReader(buf)

			header, err := reader.ReadMIMEHeader()
			if err != nil {
				session.logger.Fatalf("Error reading call info: %s", err.Error())
				continue
			}

			call := NewCall(&conn, header, session.logger)
			calls_active = append(calls_active, call)

			replyCh := make(chan CommandStatus, 100) //si +OK es "" de lo contrario se envia cade
			call.SetReply(&replyCh)

			go HandleCall(call, buf, replyCh)
			//preludio
			call.Write([]byte("linger\n\n"))
			call.Reply()
			call.Write([]byte("myevents\n\n"))
			call.Reply()

			go handler(call)
		}

		//esperamos que terminen todas las llamadas activas
		//antes de cerrar
		for _,call_active := range calls_active {
			if call_active != nil {
				<- call_active.done
			}
		}
		session.done <- true
	}(session)

}

//Termina el servidor y bloquea hasta
//que se terminen todas las llamadas
func (session *Session) Stop() bool {
	session.done <- true
	return <- session.done
}

type CommandStatus string

func HandleCall(call *Call, buf *bufio.Reader, replyCh chan CommandStatus){
	defer call.Conn.Close()

	reader := textproto.NewReader(buf)
	for {
		notification_body := ""
		notification,err := reader.ReadMIMEHeader()
		if err != nil {
			call.logger.Println("Failed read: ", err.Error())
			break
		}
		if Scontent_length := notification.Get("Content-Length"); Scontent_length != "" {
			content_length, _ := strconv.Atoi(Scontent_length)
			lreader := io.LimitReader(buf, int64(content_length))
			body, err := ioutil.ReadAll(lreader)
			if err != nil {
				call.logger.Fatalf("Failed read body: %s" ,err.Error())
				break
			}else{
				notification_body = string(body)
			}

		}

		switch notification.Get("Content-Type") {
		case "command/reply":
			if strings.HasPrefix(notification.Get("Reply-Text"), "+OK") {
				replyCh <- ""
			}else{
				replyCh <- CommandStatus(strings.TrimPrefix(notification.Get("Reply-Text"), "-ERR"))
			}
		case "text/event-plain":
			buf := bufio.NewReader(strings.NewReader(notification_body))
			reader := textproto.NewReader(buf)
			mime_body, _ := reader.ReadMIMEHeader()
			eventDispatch(call, EventFromMIME(call, mime_body))
		}
	}
}

//Crea el servidor en la interfaz y puerto seleccionado
func NewFS(laddr string, logger *log.Logger ) (* Session, error) {
	srv, err := net.Listen("tcp", laddr)
	if err != nil {
		return nil, err
	}
	return NewSession(&srv, logger), nil
}

<commit_msg>userdata en manejo de llamada<commit_after>//Implemanta Respuesta para Freeswitch Outbound e Inbound
//La idea inicial, es hacer un clon de plivoframework sencillo
//pero la diferencia es que recibe todo el mensaje o IVR
//y lo ejecuta
package glivo

import (
	"net"
	"net/textproto"
	"bufio"
	"strings"
	"io"
	"io/ioutil"
	"strconv"
	"log"
)

//Una session representa un puerto escuchando peticiones de freeswitch
type Session struct {
	listener *net.Listener
	done chan bool
	logger *log.Logger
}

func NewSession(srv *net.Listener, logger *log.Logger) *Session {
	return &Session{srv,  make(chan bool), logger}
}

func (session *Session) Start(handler func(call *Call, userData interface{}), userData interface{}) {

	go func(session *Session){
		calls_active := make([]*Call, 100, 254)
		for {
			select{
			case <-session.done:
				session.logger.Print("Closing server")
				return;
			default:
			}

			conn, err := (*session.listener).Accept()
			if err != nil {
				continue
			}

			conn.Write([]byte("connect\n\n"))
			buf := bufio.NewReaderSize(conn, 4096)
			reader := textproto.NewReader(buf)

			header, err := reader.ReadMIMEHeader()
			if err != nil {
				session.logger.Fatalf("Error reading call info: %s", err.Error())
				continue
			}

			call := NewCall(&conn, header, session.logger)
			calls_active = append(calls_active, call)

			replyCh := make(chan CommandStatus, 100) //si +OK es "" de lo contrario se envia cade
			call.SetReply(&replyCh)

			go HandleCall(call, buf, replyCh)
			//preludio
			call.Write([]byte("linger\n\n"))
			call.Reply()
			call.Write([]byte("myevents\n\n"))
			call.Reply()

			go handler(call)
		}

		//esperamos que terminen todas las llamadas activas
		//antes de cerrar
		for _,call_active := range calls_active {
			if call_active != nil {
				<- call_active.done
			}
		}
		session.done <- true
	}(session)

}

//Termina el servidor y bloquea hasta
//que se terminen todas las llamadas
func (session *Session) Stop() bool {
	session.done <- true
	return <- session.done
}

type CommandStatus string

func HandleCall(call *Call, buf *bufio.Reader, replyCh chan CommandStatus){
	defer call.Conn.Close()

	reader := textproto.NewReader(buf)
	for {
		notification_body := ""
		notification,err := reader.ReadMIMEHeader()
		if err != nil {
			call.logger.Println("Failed read: ", err.Error())
			break
		}
		if Scontent_length := notification.Get("Content-Length"); Scontent_length != "" {
			content_length, _ := strconv.Atoi(Scontent_length)
			lreader := io.LimitReader(buf, int64(content_length))
			body, err := ioutil.ReadAll(lreader)
			if err != nil {
				call.logger.Fatalf("Failed read body: %s" ,err.Error())
				break
			}else{
				notification_body = string(body)
			}

		}

		switch notification.Get("Content-Type") {
		case "command/reply":
			if strings.HasPrefix(notification.Get("Reply-Text"), "+OK") {
				replyCh <- ""
			}else{
				replyCh <- CommandStatus(strings.TrimPrefix(notification.Get("Reply-Text"), "-ERR"))
			}
		case "text/event-plain":
			buf := bufio.NewReader(strings.NewReader(notification_body))
			reader := textproto.NewReader(buf)
			mime_body, _ := reader.ReadMIMEHeader()
			eventDispatch(call, EventFromMIME(call, mime_body))
		}
	}
}

//Crea el servidor en la interfaz y puerto seleccionado
func NewFS(laddr string, logger *log.Logger ) (* Session, error) {
	srv, err := net.Listen("tcp", laddr)
	if err != nil {
		return nil, err
	}
	return NewSession(&srv, logger), nil
}

<|endoftext|>


<commit_before>// Package driver holds the driver interface.
package driver

import (
	"errors"
	"fmt"
	neturl "net/url" // alias to allow `url string` func signature in New

	"github.com/divoxx/migrate/driver/mysql"
	"github.com/divoxx/migrate/file"
)

// Driver is the interface type that needs to implemented by all drivers.
type Driver interface {

	// Initialize is the first function to be called.
	// Check the url string and open and verify any connection
	// that has to be made.
	Initialize(url string) error

	// Close is the last function to be called.
	// Close any open connection here.
	Close() error

	// FilenameExtension returns the extension of the migration files.
	// The returned string must not begin with a dot.
	FilenameExtension() string

	// Migrate is the heart of the driver.
	// It will receive a file which the driver should apply
	// to its backend or whatever. The migration function should use
	// the pipe channel to return any errors or other useful information.
	Migrate(file file.File, pipe chan interface{})

	// Version returns the current migration version.
	Version() (uint64, error)
}

// New returns Driver and calls Initialize on it
func New(url string) (Driver, error) {
	u, err := neturl.Parse(url)
	if err != nil {
		return nil, err
	}

	switch u.Scheme {
	case "postgres":
		d := &postgres.Driver{}
		verifyFilenameExtension("postgres", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil

	case "mysql":
		d := &mysql.Driver{}
		verifyFilenameExtension("mysql", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil

	case "bash":
		d := &bash.Driver{}
		verifyFilenameExtension("bash", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil

	case "cassandra":
		d := &cassandra.Driver{}
		verifyFilenameExtension("cassanda", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil
	case "sqlite3":
		d := &sqlite3.Driver{}
		verifyFilenameExtension("sqlite3", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil
	default:
		return nil, errors.New(fmt.Sprintf("Driver '%s' not found.", u.Scheme))
	}
}

// verifyFilenameExtension panics if the drivers filename extension
// is not correct or empty.
func verifyFilenameExtension(driverName string, d Driver) {
	f := d.FilenameExtension()
	if f == "" {
		panic(fmt.Sprintf("%s.FilenameExtension() returns empty string.", driverName))
	}
	if f[0:1] == "." {
		panic(fmt.Sprintf("%s.FilenameExtension() returned string must not start with a dot.", driverName))
	}
}
<commit_msg>Forgot to remove this<commit_after>// Package driver holds the driver interface.
package driver

import (
	"errors"
	"fmt"
	neturl "net/url" // alias to allow `url string` func signature in New

	"github.com/divoxx/migrate/driver/mysql"
	"github.com/divoxx/migrate/file"
)

// Driver is the interface type that needs to implemented by all drivers.
type Driver interface {

	// Initialize is the first function to be called.
	// Check the url string and open and verify any connection
	// that has to be made.
	Initialize(url string) error

	// Close is the last function to be called.
	// Close any open connection here.
	Close() error

	// FilenameExtension returns the extension of the migration files.
	// The returned string must not begin with a dot.
	FilenameExtension() string

	// Migrate is the heart of the driver.
	// It will receive a file which the driver should apply
	// to its backend or whatever. The migration function should use
	// the pipe channel to return any errors or other useful information.
	Migrate(file file.File, pipe chan interface{})

	// Version returns the current migration version.
	Version() (uint64, error)
}

// New returns Driver and calls Initialize on it
func New(url string) (Driver, error) {
	u, err := neturl.Parse(url)
	if err != nil {
		return nil, err
	}

	switch u.Scheme {
	case "mysql":
		d := &mysql.Driver{}
		verifyFilenameExtension("mysql", d)
		if err := d.Initialize(url); err != nil {
			return nil, err
		}
		return d, nil

	default:
		return nil, errors.New(fmt.Sprintf("Driver '%s' not found.", u.Scheme))
	}
}

// verifyFilenameExtension panics if the drivers filename extension
// is not correct or empty.
func verifyFilenameExtension(driverName string, d Driver) {
	f := d.FilenameExtension()
	if f == "" {
		panic(fmt.Sprintf("%s.FilenameExtension() returns empty string.", driverName))
	}
	if f[0:1] == "." {
		panic(fmt.Sprintf("%s.FilenameExtension() returned string must not start with a dot.", driverName))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
)

func ChkErr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	f, err := os.OpenFile(
		"logs/bot.log",
		os.O_RDWR|os.O_APPEND|os.O_CREATE,
		0640,
	)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	// for who.go WhoChar(char string, lvl int,
	// class string, race string, acct string)
	var char = flag.String("char", "",
		"Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0,
		"Character level for update or import. Ex: 50")
	var class = flag.String("class", "",
		"Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "",
		"Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "",
		"Character account for initial import. Ex: Krimic")
	// for who.go WhoBatch(ppl string)
	var who = flag.String("who", "",
		"Batched who output. "+
			"Ex: \"[10 Ctr] Rarac  (Orc)|[ 2 War] Xatus  (Troll)\"")
	// for identify.go Identify(filename string)
	var file = flag.String("import", "",
		"Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup string)
	var time = flag.String("time", "",
		"Parse uptime for boot tracking. Ex: 58:10:26")
	// for local.go glstat
	var glist = flag.String("glist", "",
		"Provide stats for multiple items at once. "+
			"Ex: \"a longsword|a dagger\"")
	var item = flag.String("item", "",
		"Provide stats for a single item. Ex: \"a longsword\"")
	// for tell.go ReplyTo(char string, tell string)
	var tell = flag.String("tell", "",
		"Tell with command and maybe operant. Ex: \"stat a longsword\"")
	// run database backup, restore, and parsing
	var backup = flag.Bool("bak", false,
		"Backup the toril.db database.")
	var restore = flag.String("res", "",
		"Restore the toril.db database from backup file. Ex: toril.db.gz")
	var stats = flag.Bool("s", false,
		"Run FormatStats() creation for item DB.")
	var test = flag.Bool("test", false,
		"Run any current functions under testing.")

	flag.Parse()

	var cmds []string
	// only run one command at a time
	switch {
	case *time != "":
		Uptime(*time)
	case *who != "":
		cmds = WhoBatch(*who)
	case *char != "" && *tell != "":
		cmds = ReplyTo(*char, *tell)
	case *char != "" && 50 >= *lvl && *lvl > 0 &&
		*class != "" && *race != "" && *acct != "":
		c := Char{
			name: *char, lvl: *lvl, class: *class, race: *race, acct: *acct,
		}
		cmds = c.who()
	case *stats:
		cmds = FormatStats()
	case *item != "":
		cmds = FindItem(*item, "short_stats")
	case *glist != "":
		cmds = GlistStats(*glist)
	case *file != "":
		cmds = Identify(*file)
	case *backup:
		BackupDB()
	case *restore != "":
		RestoreDB(*restore)
	case *test:
		i := Item{}
		i.FillItemByID(1)
		for _, slots := range i.slots {
			for _, slot := range slots {
				fmt.Println(slot)
			}
		}
	}
	for _, cmd := range cmds {
		fmt.Print(cmd)
	}
}
<commit_msg>Comment out port until later<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
)

func ChkErr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	f, err := os.OpenFile(
		"logs/bot.log",
		os.O_RDWR|os.O_APPEND|os.O_CREATE,
		0640,
	)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	// for who.go WhoChar(char string, lvl int,
	// class string, race string, acct string)
	var char = flag.String("char", "",
		"Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0,
		"Character level for update or import. Ex: 50")
	var class = flag.String("class", "",
		"Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "",
		"Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "",
		"Character account for initial import. Ex: Krimic")
	// for who.go WhoBatch(ppl string)
	var who = flag.String("who", "",
		"Batched who output. "+
			"Ex: \"[10 Ctr] Rarac  (Orc)|[ 2 War] Xatus  (Troll)\"")
	// for identify.go Identify(filename string)
	var file = flag.String("import", "",
		"Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup string)
	var time = flag.String("time", "",
		"Parse uptime for boot tracking. Ex: 58:10:26")
	// for local.go glstat
	var glist = flag.String("glist", "",
		"Provide stats for multiple items at once. "+
			"Ex: \"a longsword|a dagger\"")
	var item = flag.String("item", "",
		"Provide stats for a single item. Ex: \"a longsword\"")
	// for tell.go ReplyTo(char string, tell string)
	var tell = flag.String("tell", "",
		"Tell with command and maybe operant. Ex: \"stat a longsword\"")
	// run database backup, restore, and parsing
	var backup = flag.Bool("bak", false,
		"Backup the toril.db database.")
	var restore = flag.String("res", "",
		"Restore the toril.db database from backup file. Ex: toril.db.gz")
	var stats = flag.Bool("s", false,
		"Run FormatStats() creation for item DB.")
	var test = flag.Bool("test", false,
		"Run any current functions under testing.")
	// port number for API / web server
	//var port = flag.Int("port", 8080, "API / web server port.")

	flag.Parse()

	var cmds []string
	// only run one command at a time
	switch {
	case *time != "":
		Uptime(*time)
	case *who != "":
		cmds = WhoBatch(*who)
	case *char != "" && *tell != "":
		cmds = ReplyTo(*char, *tell)
	case *char != "" && 50 >= *lvl && *lvl > 0 &&
		*class != "" && *race != "" && *acct != "":
		c := Char{
			name: *char, lvl: *lvl, class: *class, race: *race, acct: *acct,
		}
		cmds = c.who()
	case *stats:
		cmds = FormatStats()
	case *item != "":
		cmds = FindItem(*item, "short_stats")
	case *glist != "":
		cmds = GlistStats(*glist)
	case *file != "":
		cmds = Identify(*file)
	case *backup:
		BackupDB()
	case *restore != "":
		RestoreDB(*restore)
	case *test:
		i := Item{}
		i.FillItemByID(1)
		for _, slots := range i.slots {
			for _, slot := range slots {
				fmt.Println(slot)
			}
		}
	}
	for _, cmd := range cmds {
		fmt.Print(cmd)
	}
}
<|endoftext|>


<commit_before>//Package gogtm enables access to gt.m database
package gogtm

/*
#cgo CFLAGS: -I/opt/fis/6.3-001A
#cgo LDFLAGS: -L/opt/fis/6.3-001A -lgtmshr
#include <gtmxc_types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define maxstr 1048576

#ifndef NULL
#define NULL ((void *) 0)
#endif

#define CALLGTM(xyz) status = xyz ;		\
	if (0 != status ) {				\
		gtm_zstatus( msg, 2048 );			\
		snprintf(errmsg, 2048, "Failure of %s with error: %s\n", #xyz, msg); \
		return (int) status; \
	}

int cip_init(char *errmsg, int maxmsglen) {
	gtm_char_t msg[maxmsglen], err[maxmsglen];
	gtm_string_t gtminit_str;
	ci_name_descriptor gtminit;
	gtm_status_t status;

	gtminit_str.address = "gtminit";
	gtminit_str.length = sizeof("gtminit")-1;
	gtminit.rtn_name=gtminit_str;
	gtminit.handle = NULL;

	errmsg[0] = '\0';
	err[0] = '\0';

	CALLGTM (gtm_cip( &gtminit, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_init error: [%s]\n", err);
		return 100;
	}
	return 0;
} // end of cip_init

int cip_set(char *s_global, char *s_value, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmset_str, p_value;
	ci_name_descriptor gtmset;
	gtm_status_t status;

	gtmset_str.address = "gtmset";
	gtmset_str.length = sizeof("gtmset")-1;
	gtmset.rtn_name=gtmset_str;
	gtmset.handle = NULL;

	err[0] = '\0';

	p_value.address = ( gtm_char_t *) s_value; p_value.length = strlen(s_value);
	CALLGTM( gtm_cip( &gtmset, s_global, &p_value, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_set error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_set

int cip_get(char *s_global, char *s_opt, char *s_ret, char *errmsg, int maxmsglen, int maxretlen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmget_str, p_opt;
	ci_name_descriptor gtmget;
	gtm_status_t status;

	gtmget_str.address = "gtmget";
	gtmget_str.length = sizeof("gtmget")-1;
	gtmget.rtn_name=gtmget_str;
	gtmget.handle = NULL;

	err[0] = '\0';

	p_opt.address = ( gtm_char_t *) s_opt; p_opt.length = strlen(s_opt);

	CALLGTM( gtm_cip( &gtmget, s_global, &p_opt, s_ret, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_get error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_get

int cip_kill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmkill_str;
	ci_name_descriptor gtmkill;
	gtm_status_t status;

	gtmkill_str.address = "gtmkill";
	gtmkill_str.length = sizeof("gtmkill")-1;
	gtmkill.rtn_name=gtmkill_str;
	gtmkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_kill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_kill

int cip_zkill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmzkill_str;
	ci_name_descriptor gtmzkill;
	gtm_status_t status;

	gtmzkill_str.address = "gtmzkill";
	gtmzkill_str.length = sizeof("gtmzkill")-1;
	gtmzkill.rtn_name=gtmzkill_str;
	gtmzkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmzkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_zkill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_zkill

int cip_xecute(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmxecute_str;
	ci_name_descriptor gtmxecute;
	gtm_status_t status;

	gtmxecute_str.address = "gtmxecute";
	gtmxecute_str.length = sizeof("gtmxecute")-1;
	gtmxecute.rtn_name=gtmxecute_str;
	gtmxecute.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmxecute, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_xecute error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_xecute

int cip_order(char *s_global, char *s_ret, char *errmsg, int maxmsglen, int maxretlen, char *direction) {
        gtm_char_t err[maxmsglen], msg[maxmsglen];
        gtm_string_t gtmorder_str, p_opt;
        ci_name_descriptor gtmorder;
        gtm_status_t status;

        gtmorder_str.address = "gtmorder";
        gtmorder_str.length = sizeof("gtmorder")-1;
        gtmorder.rtn_name=gtmorder_str;
        gtmorder.handle = NULL;

        err[0] = '\0';

        CALLGTM( gtm_cip( &gtmorder, s_global, direction, s_ret, &err));

        if (0 != strlen( err )){
                snprintf(errmsg, maxmsglen, "cip_order error: [%s]\n", err);
                fprintf( stderr, "error set: %s", err);
                return 100;
        }
        return 0;
} // end of cip_order

*/
import "C"

import (
  "unsafe"
  "errors"
//  "fmt"
//  "strconv"
)

//maxmsglen maximum length of message from gt.m
const maxmsglen = 2048

//maxretlen maximum length of value retrieved from gt.m
const maxretlen = 1048576

//Set saves value to global in gt.m db
//Sample usage: gogtm.Set("^test","value")
func Set(global string, val string) (error){

  if len(global) < 1 {
    return errors.New("Set failed - you must provide glvn")
  }

  _global := C.CString(global)
  _val := C.CString(val)
  errmsg := make([]byte, maxmsglen)

  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_val))

  result := C.cip_set(_global, _val, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Set failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Set

func Get(global string, opt string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Get failed - you must provide glvn")
  }

  _global := C.CString(global)
  _opt := C.CString(opt)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_opt))

  p := C.malloc(C.size_t(maxmsglen))
  defer C.free(p)

  result := C.cip_get(_global, _opt, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Get

func Start() (error) {
  {
  result := C.gtm_init()
  if result != 0 {
    return errors.New("gtm_init failed: " + string(result))
  }
  }
  errmsg := C.CString("")
  defer C.free(unsafe.Pointer(errmsg))

  result := C.cip_init(errmsg, maxmsglen)
  if result != 0 {
    return errors.New("CIP Init failed: " + string(result) + "Error MSG: " + C.GoString(errmsg))
  }
  return nil
} // end of Start

func Stop() (error){

  result := C.gtm_exit()

  if result != 0 {
    return errors.New("gtm_exit failed: " + string(result))
  }
  return nil
} // end of Stop

//Kill deletes global variable and its descendant nodes
func Kill(global string) (error){

  if len(global) < 1 {
    return errors.New("Kill failed - you must provide [glvn | (glvn[,...]) | *lname | *lvn ]")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_kill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Kill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Kill

//ZKill deletes global variable and its descendant nodes
func ZKill(global string) (error){

  if len(global) < 1 {
    return errors.New("ZKill failed - you must provide glvn")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_zkill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("ZKill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of ZKill

//Xecute runs the M code
func Xecute(code string) (error){

  if len(code) < 1 {
    return errors.New("Xecute failed - you must provide some code")
  }

  _code := C.CString(code)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_code))

  result := C.cip_xecute(_code, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Xecute failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Xecute

func Order(global string, dir string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Order failed - you must provide glvn")
  }

  if dir != "-1" {
    dir = "1"
  }

  _global := C.CString(global)
  _dir := C.CString(dir)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_dir))

  result := C.cip_order(_global, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen, _dir)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Order
<commit_msg>Dodane przywracanie terminala do stanu przed inicjalizacją gt.m<commit_after>//Package gogtm enables access to gt.m database
package gogtm

/*
#cgo CFLAGS: -I/opt/fis/6.3-001A
#cgo LDFLAGS: -L/opt/fis/6.3-001A -lgtmshr
#include <gtmxc_types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define maxstr 1048576

#ifndef NULL
#define NULL ((void *) 0)
#endif

#define CALLGTM(xyz) status = xyz ;		\
	if (0 != status ) {				\
		gtm_zstatus( msg, 2048 );			\
		snprintf(errmsg, 2048, "Failure of %s with error: %s\n", #xyz, msg); \
		return (int) status; \
	}

int cip_init(char *errmsg, int maxmsglen) {
	gtm_char_t msg[maxmsglen], err[maxmsglen];
	gtm_string_t gtminit_str;
	ci_name_descriptor gtminit;
	gtm_status_t status;

	gtminit_str.address = "gtminit";
	gtminit_str.length = sizeof("gtminit")-1;
	gtminit.rtn_name=gtminit_str;
	gtminit.handle = NULL;

	errmsg[0] = '\0';
	err[0] = '\0';

	CALLGTM (gtm_cip( &gtminit, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_init error: [%s]\n", err);
		return 100;
	}
	return 0;
} // end of cip_init

int cip_set(char *s_global, char *s_value, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmset_str, p_value;
	ci_name_descriptor gtmset;
	gtm_status_t status;

	gtmset_str.address = "gtmset";
	gtmset_str.length = sizeof("gtmset")-1;
	gtmset.rtn_name=gtmset_str;
	gtmset.handle = NULL;

	err[0] = '\0';

	p_value.address = ( gtm_char_t *) s_value; p_value.length = strlen(s_value);
	CALLGTM( gtm_cip( &gtmset, s_global, &p_value, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_set error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_set

int cip_get(char *s_global, char *s_opt, char *s_ret, char *errmsg, int maxmsglen, int maxretlen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmget_str, p_opt;
	ci_name_descriptor gtmget;
	gtm_status_t status;

	gtmget_str.address = "gtmget";
	gtmget_str.length = sizeof("gtmget")-1;
	gtmget.rtn_name=gtmget_str;
	gtmget.handle = NULL;

	err[0] = '\0';

	p_opt.address = ( gtm_char_t *) s_opt; p_opt.length = strlen(s_opt);

	CALLGTM( gtm_cip( &gtmget, s_global, &p_opt, s_ret, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_get error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_get

int cip_kill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmkill_str;
	ci_name_descriptor gtmkill;
	gtm_status_t status;

	gtmkill_str.address = "gtmkill";
	gtmkill_str.length = sizeof("gtmkill")-1;
	gtmkill.rtn_name=gtmkill_str;
	gtmkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_kill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_kill

int cip_zkill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmzkill_str;
	ci_name_descriptor gtmzkill;
	gtm_status_t status;

	gtmzkill_str.address = "gtmzkill";
	gtmzkill_str.length = sizeof("gtmzkill")-1;
	gtmzkill.rtn_name=gtmzkill_str;
	gtmzkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmzkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_zkill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_zkill

int cip_xecute(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmxecute_str;
	ci_name_descriptor gtmxecute;
	gtm_status_t status;

	gtmxecute_str.address = "gtmxecute";
	gtmxecute_str.length = sizeof("gtmxecute")-1;
	gtmxecute.rtn_name=gtmxecute_str;
	gtmxecute.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmxecute, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_xecute error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_xecute

int cip_order(char *s_global, char *s_ret, char *errmsg, int maxmsglen, int maxretlen, char *direction) {
        gtm_char_t err[maxmsglen], msg[maxmsglen];
        gtm_string_t gtmorder_str, p_opt;
        ci_name_descriptor gtmorder;
        gtm_status_t status;

        gtmorder_str.address = "gtmorder";
        gtmorder_str.length = sizeof("gtmorder")-1;
        gtmorder.rtn_name=gtmorder_str;
        gtmorder.handle = NULL;

        err[0] = '\0';

        CALLGTM( gtm_cip( &gtmorder, s_global, direction, s_ret, &err));

        if (0 != strlen( err )){
                snprintf(errmsg, maxmsglen, "cip_order error: [%s]\n", err);
                fprintf( stderr, "error set: %s", err);
                return 100;
        }
        return 0;
} // end of cip_order

*/
import "C"

import (
	"errors"
	"os"
	"unsafe"

	"golang.org/x/crypto/ssh/terminal"
)

//maxmsglen maximum length of message from gt.m
const maxmsglen = 2048

//maxretlen maximum length of value retrieved from gt.m
const maxretlen = 1048576

//global variables to store state of the terminal before gt.m init
var fd uintptr
var termAtStart *terminal.State

//Set saves value to global in gt.m db
//Sample usage: gogtm.Set("^test","value")
func Set(global string, val string) error {

	if len(global) < 1 {
		return errors.New("Set failed - you must provide glvn")
	}

	_global := C.CString(global)
	_val := C.CString(val)
	errmsg := make([]byte, maxmsglen)

	defer C.free(unsafe.Pointer(_global))
	defer C.free(unsafe.Pointer(_val))

	result := C.cip_set(_global, _val, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

	if result != 0 {
		return errors.New("Set failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return nil
} // end of Set

//Get the value of provided glvn
func Get(global string, opt string) (string, error) {

	if len(global) < 1 {
		return "", errors.New("Get failed - you must provide glvn")
	}

	_global := C.CString(global)
	_opt := C.CString(opt)
	_ret := make([]byte, maxretlen)
	errmsg := make([]byte, maxmsglen)
	defer C.free(unsafe.Pointer(_global))
	defer C.free(unsafe.Pointer(_opt))

	p := C.malloc(C.size_t(maxmsglen))
	defer C.free(p)

	result := C.cip_get(_global, _opt, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen)

	if result != 0 {
		return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return string(_ret), nil
} //end of Get

//Start should be used as the initiator of connection to gt.m
func Start() error {
	fd = os.Stdin.Fd()
	termAtStart, _ = terminal.GetState(int(fd))
	{
		result := C.gtm_init()
		if result != 0 {
			return errors.New("gtm_init failed: " + string(result))
		}
	}
	errmsg := C.CString("")
	defer C.free(unsafe.Pointer(errmsg))

	result := C.cip_init(errmsg, maxmsglen)
	if result != 0 {
		return errors.New("CIP Init failed: " + string(result) + "Error MSG: " + C.GoString(errmsg))
	}
	return nil
} // end of Start

//Stop closes the connection gently.
func Stop() error {

	result := C.gtm_exit()

	if result != 0 {
		return errors.New("gtm_exit failed: " + string(result))
	}
	terminal.Restore(int(fd), termAtStart)
	return nil
} // end of Stop

//Kill deletes global variable and its descendant nodes
func Kill(global string) error {

	if len(global) < 1 {
		return errors.New("Kill failed - you must provide [glvn | (glvn[,...]) | *lname | *lvn ]")
	}

	_global := C.CString(global)
	errmsg := make([]byte, maxmsglen)
	defer C.free(unsafe.Pointer(_global))

	result := C.cip_kill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

	if result != 0 {
		return errors.New("Kill failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return nil
} // end of Kill

//ZKill deletes global variable and its descendant nodes
func ZKill(global string) error {

	if len(global) < 1 {
		return errors.New("ZKill failed - you must provide glvn")
	}

	_global := C.CString(global)
	errmsg := make([]byte, maxmsglen)
	defer C.free(unsafe.Pointer(_global))

	result := C.cip_zkill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

	if result != 0 {
		return errors.New("ZKill failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return nil
} // end of ZKill

//Xecute runs the M code
func Xecute(code string) error {

	if len(code) < 1 {
		return errors.New("Xecute failed - you must provide some code")
	}

	_code := C.CString(code)
	errmsg := make([]byte, maxmsglen)
	defer C.free(unsafe.Pointer(_code))

	result := C.cip_xecute(_code, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

	if result != 0 {
		return errors.New("Xecute failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return nil
} // end of Xecute

//Order returns the next key or glvn
func Order(global string, dir string) (string, error) {

	if len(global) < 1 {
		return "", errors.New("Order failed - you must provide glvn")
	}

	if dir != "-1" {
		dir = "1"
	}

	_global := C.CString(global)
	_dir := C.CString(dir)
	_ret := make([]byte, maxretlen)
	errmsg := make([]byte, maxmsglen)
	defer C.free(unsafe.Pointer(_global))
	defer C.free(unsafe.Pointer(_dir))

	result := C.cip_order(_global, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen, _dir)

	if result != 0 {
		return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
	}
	return string(_ret), nil
} //end of Order
<|endoftext|>


<commit_before>package golis

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
)

//系统变量定义

var (
	GolisHandler IoHandler //事件处理
	GolisMsg     Message   //消息协议
)

//消息协议
type Message interface {
	Unpacket([]byte) interface{}
	Packet(interface{}) []byte
}

//定义session
type Iosession struct {
	conn net.Conn
}

//session写入数据
func (this *Iosession) Write(message *interface{}) {
	//触发消息发送事件
	GolisHandler.MessageSent(this, message)
	data := GolisMsg.Packet(message)
	totalLen := len(data)
	this.conn.Write(append(IntToBytes(totalLen), data...))
}

//事件触发接口定义
type IoHandler interface {
	//session打开
	SessionOpened(session *Iosession)
	//session关闭
	SessionClosed(session *Iosession)
	//收到消息时触发
	MessageReceived(session *Iosession, message interface{})
	//消息发送时触发
	MessageSent(session *Iosession, message interface{})
}

//运行golis
//netPro：运行协议参数，tcp/udp
//laddr ：程序监听ip和端口，如127.0.0.1:8080
func Run(netPro, laddr string) {
	Log("初始化系统完成")
	netLis, err := net.Listen(netPro, laddr)
	CheckError(err)
	defer netLis.Close()
	Log("等待客户端连接...")
	for {
		conn, err := netLis.Accept()
		if err != nil {
			continue
		}
		go connectHandle(conn)
	}
}

//处理新连接
func connectHandle(conn net.Conn) {
	//声明一个临时缓冲区，用来存储被截断的数据
	tmpBuffer := make([]byte, 0)
	buffer := make([]byte, 1024)
	//创建session
	session := Iosession{conn}
	//触发sessionCreated事件
	GolisHandler.SessionOpened(&session)

	flag := true
	for flag {
		n, err := conn.Read(buffer)
		switch err {
		case nil:
			tmp, data, err := getReadyData(append(tmpBuffer, buffer[:n]...))
			tmpBuffer = tmp
			if err != nil {
				Log(err.Error())
			} else {
				readFromData(&session, data)
			}
		case io.EOF:
			Log("client is disconnected")
			//session关闭
			GolisHandler.SessionClosed(&session)
			flag = false
			break
		default:
			Log("none")
		}
	}

}

//协议中查看协议头是否满足一个协议报
func getReadyData(buffer []byte) ([]byte, []byte, error) {
	length := len(buffer)
	if length >= 32 {
		totalLen := BytesToInt(buffer[0:32]) //get totalLen
		if totalLen == 0 {
			return make([]byte, 0), nil, errors.New("msg is null")
		} else if totalLen <= length-32 {
			return buffer[totalLen+32:], buffer[32:totalLen], nil
		}

	}
	return buffer, nil, errors.New("msg is not ready")
}

//从准备好的数据读取
func readFromData(session *Iosession, data []byte) {
	message := GolisMsg.Unpacket(data) //拆包
	//收到消息时到达
	GolisHandler.MessageReceived(session, message)
}

//整形转换成字节
func IntToBytes(n int) []byte {
	x := int32(n)

	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.BigEndian, x)
	return bytesBuffer.Bytes()
}

//字节转换成整形
func BytesToInt(b []byte) int {
	bytesBuffer := bytes.NewBuffer(b)

	var x int32
	binary.Read(bytesBuffer, binary.BigEndian, &x)

	return int(x)
}

//简单日志输出
func Log(v ...interface{}) {
	fmt.Println(v...)
}

//检查错误并退出程序
func CheckError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, "Fatal error:%s", err.Error())
		os.Exit(1)
	}
}
<commit_msg>*修改拆包解包方式<commit_after>package golis

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
)

//系统变量定义

var (
	GolisHandler IoHandler                //事件处理
	Unpacket     func([]byte) interface{} //拆包
	Packet       func(interface{}) []byte //封包
)

//定义session
type Iosession struct {
	conn net.Conn
}

//session写入数据
func (this *Iosession) Write(message *interface{}) {
	//触发消息发送事件
	GolisHandler.MessageSent(this, message)
	data := Packet(message)
	totalLen := len(data)
	this.conn.Write(append(IntToBytes(totalLen), data...))
}

//事件触发接口定义
type IoHandler interface {
	//session打开
	SessionOpened(session *Iosession)
	//session关闭
	SessionClosed(session *Iosession)
	//收到消息时触发
	MessageReceived(session *Iosession, message interface{})
	//消息发送时触发
	MessageSent(session *Iosession, message interface{})
}

//运行golis
//netPro：运行协议参数，tcp/udp
//laddr ：程序监听ip和端口，如127.0.0.1:8080
func Run(netPro, laddr string) {
	Log("初始化系统完成")
	netLis, err := net.Listen(netPro, laddr)
	CheckError(err)
	defer netLis.Close()
	Log("等待客户端连接...")
	for {
		conn, err := netLis.Accept()
		if err != nil {
			continue
		}
		go connectHandle(conn)
	}
}

//处理新连接
func connectHandle(conn net.Conn) {
	//声明一个临时缓冲区，用来存储被截断的数据
	tmpBuffer := make([]byte, 0)
	buffer := make([]byte, 1024)
	//创建session
	session := Iosession{conn}
	//触发sessionCreated事件
	GolisHandler.SessionOpened(&session)

	flag := true
	for flag {
		n, err := conn.Read(buffer)
		switch err {
		case nil:
			tmp, data, err := getReadyData(append(tmpBuffer, buffer[:n]...))
			tmpBuffer = tmp
			if err != nil {
				Log(err.Error())
			} else {
				readFromData(&session, data)
			}
		case io.EOF:
			Log("client is disconnected")
			//session关闭
			GolisHandler.SessionClosed(&session)
			flag = false
			break
		default:
			Log("none")
		}
	}

}

//协议中查看协议头是否满足一个协议报
func getReadyData(buffer []byte) ([]byte, []byte, error) {
	length := len(buffer)
	if length >= 32 {
		totalLen := BytesToInt(buffer[0:32]) //get totalLen
		if totalLen == 0 {
			return make([]byte, 0), nil, errors.New("msg is null")
		} else if totalLen <= length-32 {
			return buffer[totalLen+32:], buffer[32:totalLen], nil
		}

	}
	return buffer, nil, errors.New("msg is not ready")
}

//从准备好的数据读取
func readFromData(session *Iosession, data []byte) {
	message := Unpacket(data) //拆包
	//收到消息时到达
	GolisHandler.MessageReceived(session, message)
}

//整形转换成字节
func IntToBytes(n int) []byte {
	x := int32(n)

	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.BigEndian, x)
	return bytesBuffer.Bytes()
}

//字节转换成整形
func BytesToInt(b []byte) int {
	bytesBuffer := bytes.NewBuffer(b)

	var x int32
	binary.Read(bytesBuffer, binary.BigEndian, &x)

	return int(x)
}

//简单日志输出
func Log(v ...interface{}) {
	fmt.Println(v...)
}

//检查错误并退出程序
func CheckError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, "Fatal error:%s", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>
package golog

import (
    "io"
    "io/ioutil"
    "log"
    "os"
    "fmt"
    "strings"
    "time"
    "sync/atomic"
)
const (
	// everything
	LevelTrace int32 = 1

	// Info, Warnings and Errors
	LevelInfo int32 = 2

	// Warning and Errors
	LevelWarn int32 = 4

	// Errors
	LevelError int32 = 8
)

// goLogStruct provides support to write to log files.
type goLogStruct struct {
	LogLevel           int32
	Trace              *log.Logger
	Info               *log.Logger
	Warning            *log.Logger
	Error              *log.Logger
	File               *log.Logger
	LogFile            *os.File
}

// log maintains a pointer to a singleton for the logging system.
var logger goLogStruct

// Called to init the logging system.
func (lS goLogStruct) Init(logLevel int32, baseFilePath string) error {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	err := startFile(logLevel, baseFilePath)
	if err != nil
		return err;
	lS = logger
	return
}

// StartFile initializes goLogStruct and only displays the specified logging level
// and creates a file to capture writes.
func startFile(logLevel int32, baseFilePath string) error {
	baseFilePath = strings.TrimRight(baseFilePath, "/")
	currentDate := time.Now().UTC()
	dateDirectory := time.Now().UTC().Format("2006-01-02")
	dateFile := currentDate.Format("2006-01-02T15-04-05")

	filePath := fmt.Sprintf("%s/%s/", baseFilePath, dateDirectory)
	fileName := strings.Replace(fmt.Sprintf("%s.txt", dateFile), " ", "-", -1)

	err := os.MkdirAll(filePath, os.ModePerm)
	if err != nil {
		log.Fatalf("main : Start : Failed to Create log directory : %s : %s\n", filePath, err)
		return err
	}

	logf, err := os.Create(fmt.Sprintf("%s%s", filePath, fileName))
	if err != nil {
		log.Fatalf("main : Start : Failed to Create log file : %s : %s\n", fileName, err)
		return err
	}

	turnOnLogging(logLevel, logf)
	return

}

// Stop will release resources and shutdown all processing.
func Stop() error {
	var err error
	if logger.LogFile != nil {
		Trace("main", "Stop", "Closing File")
		err = logger.LogFile.Close()
	}
	return err
}

// LogLevel returns the configured logging level.
func GetLogLevel() int32 {
	return atomic.LoadInt32(&logger.LogLevel)
}

// turnOnLogging configures the logging writers.
func turnOnLogging(logLevel int32, fileHandle io.Writer) {
	traceHandle := ioutil.Discard
	infoHandle := ioutil.Discard
	warnHandle := ioutil.Discard
	errorHandle := ioutil.Discard

	if logLevel&LevelTrace != 0 {
		traceHandle = os.Stdout
		infoHandle = os.Stdout
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelInfo != 0 {
		infoHandle = os.Stdout
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelWarn != 0 {
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelError != 0 {
		errorHandle = os.Stderr
	}

	if fileHandle != nil {
		if traceHandle == os.Stdout {
			traceHandle = io.MultiWriter(fileHandle, traceHandle)
		}

		if infoHandle == os.Stdout {
			infoHandle = io.MultiWriter(fileHandle, infoHandle)
		}

		if warnHandle == os.Stdout {
			warnHandle = io.MultiWriter(fileHandle, warnHandle)
		}

		if errorHandle == os.Stderr {
			errorHandle = io.MultiWriter(fileHandle, errorHandle)
		}
	}

	logger.Trace = log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Info = log.New(infoHandle, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Warning = log.New(warnHandle, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Error = log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)

	atomic.StoreInt32(&logger.LogLevel, logLevel)
}

//** TRACE

// Trace writes to the Trace destination
func Trace(format string, a ...interface{}) {
	logger.Trace.Output(2, fmt.Sprintf("%s\n", fmt.Sprintf(format, a...)))
}

//** INFO

// Info writes to the Info destination
func Info(format string, a ...interface{}) {
	logger.Info.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//** WARNING

// Warning writes to the Warning destination
func Warning(format string, a ...interface{}) {
	logger.Warning.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//** ERROR

// Error writes to the Error destination and accepts an err
func Error(format string, a ...interface{}) {
	logger.Error.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//writes to the Error and exit(1)
func Fatal(format string, a ...interface{}) {
	logger.Error.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
	os.Exit(1)
}

<commit_msg>more corrections<commit_after>
package golog

import (
    "io"
    "io/ioutil"
    "log"
    "os"
    "fmt"
    "strings"
    "time"
    "sync/atomic"
)
const (
	// everything
	LevelTrace int32 = 1

	// Info, Warnings and Errors
	LevelInfo int32 = 2

	// Warning and Errors
	LevelWarn int32 = 4

	// Errors
	LevelError int32 = 8
)

// goLogStruct provides support to write to log files.
type goLogStruct struct {
	LogLevel           int32
	Trace              *log.Logger
	Info               *log.Logger
	Warning            *log.Logger
	Error              *log.Logger
	File               *log.Logger
	LogFile            *os.File
}

// log maintains a pointer to a singleton for the logging system.
var logger goLogStruct

// Called to init the logging system.
func (lS goLogStruct) Init(logLevel int32, baseFilePath string) error {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	err := startFile(logLevel, baseFilePath)
	if err != nil {
		return err;
	}
	lS = logger
	return err
}

// StartFile initializes goLogStruct and only displays the specified logging level
// and creates a file to capture writes.
func startFile(logLevel int32, baseFilePath string) error {
	baseFilePath = strings.TrimRight(baseFilePath, "/")
	currentDate := time.Now().UTC()
	dateDirectory := time.Now().UTC().Format("2006-01-02")
	dateFile := currentDate.Format("2006-01-02T15-04-05")

	filePath := fmt.Sprintf("%s/%s/", baseFilePath, dateDirectory)
	fileName := strings.Replace(fmt.Sprintf("%s.txt", dateFile), " ", "-", -1)

	err := os.MkdirAll(filePath, os.ModePerm)
	if err != nil {
		log.Fatalf("main : Start : Failed to Create log directory : %s : %s\n", filePath, err)
		return err
	}

	logf, err := os.Create(fmt.Sprintf("%s%s", filePath, fileName))
	if err != nil {
		log.Fatalf("main : Start : Failed to Create log file : %s : %s\n", fileName, err)
		return err
	}

	turnOnLogging(logLevel, logf)
	return err

}

// Stop will release resources and shutdown all processing.
func Stop() error {
	var err error
	if logger.LogFile != nil {
		Trace("main", "Stop", "Closing File")
		err = logger.LogFile.Close()
	}
	return err
}

// LogLevel returns the configured logging level.
func GetLogLevel() int32 {
	return atomic.LoadInt32(&logger.LogLevel)
}

// turnOnLogging configures the logging writers.
func turnOnLogging(logLevel int32, fileHandle io.Writer) {
	traceHandle := ioutil.Discard
	infoHandle := ioutil.Discard
	warnHandle := ioutil.Discard
	errorHandle := ioutil.Discard

	if logLevel&LevelTrace != 0 {
		traceHandle = os.Stdout
		infoHandle = os.Stdout
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelInfo != 0 {
		infoHandle = os.Stdout
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelWarn != 0 {
		warnHandle = os.Stdout
		errorHandle = os.Stderr
	}

	if logLevel&LevelError != 0 {
		errorHandle = os.Stderr
	}

	if fileHandle != nil {
		if traceHandle == os.Stdout {
			traceHandle = io.MultiWriter(fileHandle, traceHandle)
		}

		if infoHandle == os.Stdout {
			infoHandle = io.MultiWriter(fileHandle, infoHandle)
		}

		if warnHandle == os.Stdout {
			warnHandle = io.MultiWriter(fileHandle, warnHandle)
		}

		if errorHandle == os.Stderr {
			errorHandle = io.MultiWriter(fileHandle, errorHandle)
		}
	}

	logger.Trace = log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Info = log.New(infoHandle, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Warning = log.New(warnHandle, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
	logger.Error = log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)

	atomic.StoreInt32(&logger.LogLevel, logLevel)
}

//** TRACE

// Trace writes to the Trace destination
func Trace(format string, a ...interface{}) {
	logger.Trace.Output(2, fmt.Sprintf("%s\n", fmt.Sprintf(format, a...)))
}

//** INFO

// Info writes to the Info destination
func Info(format string, a ...interface{}) {
	logger.Info.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//** WARNING

// Warning writes to the Warning destination
func Warning(format string, a ...interface{}) {
	logger.Warning.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//** ERROR

// Error writes to the Error destination and accepts an err
func Error(format string, a ...interface{}) {
	logger.Error.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
}

//writes to the Error and exit(1)
func Fatal(format string, a ...interface{}) {
	logger.Error.Output(2, fmt.Sprintf(fmt.Sprintf(format, a...)))
	os.Exit(1)
}

<|endoftext|>