<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/caiofilipini/encurtador/url"
	"log"
	"net/http"
	"strings"
)

var (
	logLigado *bool
	porta     *int
	urlBase   string
)

func init() {
	dominio := flag.String("d", "localhost", "domínio")
	porta = flag.Int("p", 8888, "porta")
	logLigado = flag.Bool("l", true, "log ligado/desligado")

	flag.Parse()

	urlBase = fmt.Sprintf("http://%s:%d", *dominio, *porta)
}

type Headers map[string]string

type Redirecionador struct {
	stats chan string
}

func (r *Redirecionador) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	buscarUrlEExecutar(w, req, func(url *url.Url) {
		http.Redirect(w, req, url.Destino, http.StatusMovedPermanently)
		r.stats <- url.Id
	})
}

func Encurtador(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		responderCom(w, http.StatusMethodNotAllowed, Headers{"Allow": "POST"})
		return
	}

	url, nova, err := url.BuscarOuCriarNovaUrl(extrairUrl(r))

	if err != nil {
		responderCom(w, http.StatusBadRequest, nil)
		return
	}

	var status int
	if nova {
		status = http.StatusCreated
	} else {
		status = http.StatusOK
	}

	urlCurta := fmt.Sprintf("%s/r/%s", urlBase, url.Id)

	responderCom(w, status, Headers{
		"Location": urlCurta,
		"Link":     fmt.Sprintf("<%s/api/stats/%s>; rel=\"stats\"", urlBase, url.Id),
	})

	logar("URL %s encurtada com sucesso para %s.", url.Destino, urlCurta)
}

func Visualizador(w http.ResponseWriter, r *http.Request) {
	buscarUrlEExecutar(w, r, func(url *url.Url) {
		json, err := json.Marshal(url.Stats())

		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		responderComJSON(w, string(json))
	})
}

func buscarUrlEExecutar(w http.ResponseWriter, r *http.Request, executor func(*url.Url)) {
	caminho := strings.Split(r.URL.Path, "/")
	id := caminho[len(caminho)-1]

	if url := url.Buscar(id); url != nil {
		executor(url)
	} else {
		http.NotFound(w, r)
	}
}

func responderCom(w http.ResponseWriter, status int, headers Headers) {
	for k, v := range headers {
		w.Header().Set(k, v)
	}
	w.WriteHeader(status)
}

func responderComJSON(w http.ResponseWriter, resposta string) {
	responderCom(w, http.StatusOK, Headers{"Content-Type": "application/json"})
	fmt.Fprintf(w, resposta)
}

func logar(formato string, valores ...interface{}) {
	if *logLigado {
		log.Printf(fmt.Sprintf("%s\n", formato), valores...)
	}
}

func extrairUrl(r *http.Request) string {
	rawBody := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(rawBody)
	return string(rawBody)
}

func registrarEstatisticas(stats chan string) {
	for id := range stats {
		url.RegistrarClick(id)
		log.Printf("Click registrado com sucesso para %s.\n", id)
	}
}

func main() {
	stats := make(chan string)
	defer close(stats)
	go registrarEstatisticas(stats)

	http.Handle("/r/", &Redirecionador{stats})
	http.HandleFunc("/api/encurtar", Encurtador)
	http.HandleFunc("/api/stats/", Visualizador)

	logar("Iniciando servidor na porta %d...", *porta)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *porta), nil))
}
<commit_msg>Logar tudo via método `logar()`.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/caiofilipini/encurtador/url"
	"log"
	"net/http"
	"strings"
)

var (
	logLigado *bool
	porta     *int
	urlBase   string
)

func init() {
	dominio := flag.String("d", "localhost", "domínio")
	porta = flag.Int("p", 8888, "porta")
	logLigado = flag.Bool("l", true, "log ligado/desligado")

	flag.Parse()

	urlBase = fmt.Sprintf("http://%s:%d", *dominio, *porta)
}

type Headers map[string]string

type Redirecionador struct {
	stats chan string
}

func (r *Redirecionador) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	buscarUrlEExecutar(w, req, func(url *url.Url) {
		http.Redirect(w, req, url.Destino, http.StatusMovedPermanently)
		r.stats <- url.Id
	})
}

func Encurtador(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		responderCom(w, http.StatusMethodNotAllowed, Headers{"Allow": "POST"})
		return
	}

	url, nova, err := url.BuscarOuCriarNovaUrl(extrairUrl(r))

	if err != nil {
		responderCom(w, http.StatusBadRequest, nil)
		return
	}

	var status int
	if nova {
		status = http.StatusCreated
	} else {
		status = http.StatusOK
	}

	urlCurta := fmt.Sprintf("%s/r/%s", urlBase, url.Id)

	responderCom(w, status, Headers{
		"Location": urlCurta,
		"Link":     fmt.Sprintf("<%s/api/stats/%s>; rel=\"stats\"", urlBase, url.Id),
	})

	logar("URL %s encurtada com sucesso para %s.", url.Destino, urlCurta)
}

func Visualizador(w http.ResponseWriter, r *http.Request) {
	buscarUrlEExecutar(w, r, func(url *url.Url) {
		json, err := json.Marshal(url.Stats())

		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		responderComJSON(w, string(json))
	})
}

func buscarUrlEExecutar(w http.ResponseWriter, r *http.Request, executor func(*url.Url)) {
	caminho := strings.Split(r.URL.Path, "/")
	id := caminho[len(caminho)-1]

	if url := url.Buscar(id); url != nil {
		executor(url)
	} else {
		http.NotFound(w, r)
	}
}

func responderCom(w http.ResponseWriter, status int, headers Headers) {
	for k, v := range headers {
		w.Header().Set(k, v)
	}
	w.WriteHeader(status)
}

func responderComJSON(w http.ResponseWriter, resposta string) {
	responderCom(w, http.StatusOK, Headers{"Content-Type": "application/json"})
	fmt.Fprintf(w, resposta)
}

func extrairUrl(r *http.Request) string {
	rawBody := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(rawBody)
	return string(rawBody)
}

func registrarEstatisticas(stats chan string) {
	for id := range stats {
		url.RegistrarClick(id)
		logar("Click registrado com sucesso para %s.\n", id)
	}
}

func logar(formato string, valores ...interface{}) {
	if *logLigado {
		log.Printf(fmt.Sprintf("%s\n", formato), valores...)
	}
}

func main() {
	stats := make(chan string)
	defer close(stats)
	go registrarEstatisticas(stats)

	http.Handle("/r/", &Redirecionador{stats})
	http.HandleFunc("/api/encurtar", Encurtador)
	http.HandleFunc("/api/stats/", Visualizador)

	logar("Iniciando servidor na porta %d...", *porta)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *porta), nil))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/cloudnativelabs/kube-router/app"
	"github.com/cloudnativelabs/kube-router/app/options"
	"github.com/spf13/pflag"
)

func main() {

	config := options.NewKubeRouterConfig()
	config.AddFlags(pflag.CommandLine)
	pflag.Parse()

	flag.Set("logtostderr", "true")

	if config.HelpRequested {
		pflag.Usage()
		os.Exit(0)
	}

	if os.Geteuid() != 0 {
		fmt.Fprintf(os.Stderr, "kube-router needs to be run with privileges to execute iptables, ipset and configure ipvs\n")
		os.Exit(1)
	}

	if config.CleanupConfig {
		app.CleanupConfigAndExit()
		os.Exit(0)
	}

	kubeRouter, err := app.NewKubeRouterDefault(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse kube-router config: %v\n", err)
		os.Exit(1)
	}

	err = kubeRouter.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to run kube-router: %v\n", err)
		os.Exit(1)
	}
}
<commit_msg>Use pflag only<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/cloudnativelabs/kube-router/app"
	"github.com/cloudnativelabs/kube-router/app/options"
	"github.com/spf13/pflag"
)

func main() {

	config := options.NewKubeRouterConfig()
	config.AddFlags(pflag.CommandLine)
	pflag.Parse()

	pflag.Set("logtostderr", "true")

	if config.HelpRequested {
		pflag.Usage()
		os.Exit(0)
	}

	if os.Geteuid() != 0 {
		fmt.Fprintf(os.Stderr, "kube-router needs to be run with privileges to execute iptables, ipset and configure ipvs\n")
		os.Exit(1)
	}

	if config.CleanupConfig {
		app.CleanupConfigAndExit()
		os.Exit(0)
	}

	kubeRouter, err := app.NewKubeRouterDefault(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse kube-router config: %v\n", err)
		os.Exit(1)
	}

	err = kubeRouter.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to run kube-router: %v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Songmu/retry"
	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"
)

// ErrReleaseNotFound contains the error for when a release is not found
var (
	ErrReleaseNotFound = errors.New("release is not found")
)

// GitHub contains the functions necessary for interacting with GitHub release
// objects
type GitHub interface {
	CreateRelease(ctx context.Context, req *github.RepositoryRelease) (*github.RepositoryRelease, error)
	GetRelease(ctx context.Context, tag string) (*github.RepositoryRelease, error)
	EditRelease(ctx context.Context, releaseID int64, req *github.RepositoryRelease) (*github.RepositoryRelease, error)
	DeleteRelease(ctx context.Context, releaseID int64) error
	DeleteTag(ctx context.Context, tag string) error

	UploadAsset(ctx context.Context, releaseID int64, filename string) (*github.ReleaseAsset, error)
	DeleteAsset(ctx context.Context, assetID int64) error
	ListAssets(ctx context.Context, releaseID int64) ([]*github.ReleaseAsset, error)

	SetUploadURL(urlStr string) error
}

// GitHubClient is the client for interacting with the GitHub API
type GitHubClient struct {
	Owner, Repo string
	*github.Client
}

// NewGitHubClient creates and initializes a new GitHubClient
func NewGitHubClient(owner, repo, token, urlStr string) (GitHub, error) {
	if len(owner) == 0 {
		return nil, errors.New("missing GitHub repository owner")
	}

	if len(repo) == 0 {
		return nil, errors.New("missing GitHub repository name")
	}

	if len(token) == 0 {
		return nil, errors.New("missing GitHub API token")
	}

	if len(urlStr) == 0 {
		return nil, errors.New("missing GitHub API URL")
	}

	baseURL, err := url.ParseRequestURI(urlStr)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse Github API URL")
	}

	ts := oauth2.StaticTokenSource(&oauth2.Token{
		AccessToken: token,
	})
	tc := oauth2.NewClient(context.TODO(), ts)

	client := github.NewClient(tc)
	client.BaseURL = baseURL

	return &GitHubClient{
		Owner:  owner,
		Repo:   repo,
		Client: client,
	}, nil
}

// SetUploadURL constructs the upload URL for a release
func (c *GitHubClient) SetUploadURL(urlStr string) error {
	i := strings.Index(urlStr, "repos/")
	parsedURL, err := url.ParseRequestURI(urlStr[:i])
	if err != nil {
		return errors.Wrap(err, "failed to parse upload URL")
	}

	c.UploadURL = parsedURL
	return nil
}

// CreateRelease creates a new release object in the GitHub API
func (c *GitHubClient) CreateRelease(ctx context.Context, req *github.RepositoryRelease) (*github.RepositoryRelease, error) {

	release, res, err := c.Repositories.CreateRelease(context.TODO(), c.Owner, c.Repo, req)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create a release")
	}

	if res.StatusCode != http.StatusCreated {
		return nil, errors.Errorf("create release: invalid status: %s", res.Status)
	}

	return release, nil
}

// GetRelease queries the GitHub API for a specified release object
func (c *GitHubClient) GetRelease(ctx context.Context, tag string) (*github.RepositoryRelease, error) {
	// Check Release whether already exists or not
	release, res, err := c.Repositories.GetReleaseByTag(context.TODO(), c.Owner, c.Repo, tag)
	if err != nil {
		if res == nil {
			return nil, errors.Wrapf(err, "failed to get release tag: %s", tag)
		}

		// TODO(tcnksm): Handle invalid token
		if res.StatusCode != http.StatusNotFound {
			return nil, errors.Wrapf(err,
				"get release tag: invalid status: %s", res.Status)
		}

		return nil, ErrReleaseNotFound
	}

	return release, nil
}

// EditRelease edit a release object within the GitHub API
func (c *GitHubClient) EditRelease(ctx context.Context, releaseID int64, req *github.RepositoryRelease) (*github.RepositoryRelease, error) {
	var release *github.RepositoryRelease

	err := retry.Retry(3, 3*time.Second, func() error {
		var (
			res *github.Response
			err error
		)
		release, res, err = c.Repositories.EditRelease(context.TODO(), c.Owner, c.Repo, releaseID, req)
		if err != nil {
			return errors.Wrapf(err, "failed to edit release: %d", releaseID)
		}

		if res.StatusCode != http.StatusOK {
			return errors.Errorf("edit release: invalid status: %s", res.Status)
		}
		return nil
	})
	return release, err
}

// DeleteRelease deletes a release object within the GitHub API
func (c *GitHubClient) DeleteRelease(ctx context.Context, releaseID int64) error {
	res, err := c.Repositories.DeleteRelease(context.TODO(), c.Owner, c.Repo, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to delete release")
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete release: invalid status: %s", res.Status)
	}

	return nil
}

// DeleteTag deletes a tag from the GitHub API
func (c *GitHubClient) DeleteTag(ctx context.Context, tag string) error {
	ref := fmt.Sprintf("tags/%s", tag)
	res, err := c.Git.DeleteRef(context.TODO(), c.Owner, c.Repo, ref)
	if err != nil {
		return errors.Wrapf(err, "failed to delete tag: %s", ref)
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete tag: invalid status: %s", res.Status)
	}

	return nil
}

// UploadAsset uploads specified assets to a given release object
func (c *GitHubClient) UploadAsset(ctx context.Context, releaseID int64, filename string) (*github.ReleaseAsset, error) {

	filename, err := filepath.Abs(filename)
	if err != nil {
		return nil, errors.Wrap(err, "failed to get abs path")
	}

	opts := &github.UploadOptions{
		// Use base name by default
		Name: filepath.Base(filename),
	}

	var asset *github.ReleaseAsset
	err = retry.Retry(3, 3*time.Second, func() error {
		var (
			res *github.Response
			err error
		)

		f, err := os.Open(filename)
		if err != nil {
			return errors.Wrap(err, "failed to open file")
		}

		asset, res, err = c.Repositories.UploadReleaseAsset(context.TODO(), c.Owner, c.Repo, releaseID, opts, f)
		if err != nil {
			return errors.Wrapf(err, "failed to upload release asset: %s", filename)
		}

		switch res.StatusCode {
		case http.StatusCreated:
			return nil
		case 422:
			return errors.Errorf(
				"upload release asset: invalid status code: %s",
				"422 (this is probably because the asset already uploaded)")
		default:
			return errors.Errorf(
				"upload release asset: invalid status code: %s", res.Status)
		}
	})
	return asset, err
}

// DeleteAsset deletes assets from a given release object
func (c *GitHubClient) DeleteAsset(ctx context.Context, assetID int64) error {
	res, err := c.Repositories.DeleteReleaseAsset(context.TODO(), c.Owner, c.Repo, assetID)
	if err != nil {
		return errors.Wrap(err, "failed to delete release asset")
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete release assets: invalid status code: %s", res.Status)
	}

	return nil
}

// ListAssets lists assets associated with a given release
func (c *GitHubClient) ListAssets(ctx context.Context, releaseID int64) ([]*github.ReleaseAsset, error) {
	result := []*github.ReleaseAsset{}
	page := 1

	for {
		assets, res, err := c.Repositories.ListReleaseAssets(context.TODO(), c.Owner, c.Repo, releaseID, &github.ListOptions{Page: page})
		if err != nil {
			return nil, errors.Wrap(err, "failed to list assets")
		}

		if res.StatusCode != http.StatusOK {
			return nil, errors.Errorf("list release assets: invalid status code: %s", res.Status)
		}

		result = append(result, assets...)

		if res.NextPage <= page {
			break
		}

		page = res.NextPage
	}

	return result, nil
}
<commit_msg>defer f.Close()<commit_after>package main

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Songmu/retry"
	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"
)

// ErrReleaseNotFound contains the error for when a release is not found
var (
	ErrReleaseNotFound = errors.New("release is not found")
)

// GitHub contains the functions necessary for interacting with GitHub release
// objects
type GitHub interface {
	CreateRelease(ctx context.Context, req *github.RepositoryRelease) (*github.RepositoryRelease, error)
	GetRelease(ctx context.Context, tag string) (*github.RepositoryRelease, error)
	EditRelease(ctx context.Context, releaseID int64, req *github.RepositoryRelease) (*github.RepositoryRelease, error)
	DeleteRelease(ctx context.Context, releaseID int64) error
	DeleteTag(ctx context.Context, tag string) error

	UploadAsset(ctx context.Context, releaseID int64, filename string) (*github.ReleaseAsset, error)
	DeleteAsset(ctx context.Context, assetID int64) error
	ListAssets(ctx context.Context, releaseID int64) ([]*github.ReleaseAsset, error)

	SetUploadURL(urlStr string) error
}

// GitHubClient is the client for interacting with the GitHub API
type GitHubClient struct {
	Owner, Repo string
	*github.Client
}

// NewGitHubClient creates and initializes a new GitHubClient
func NewGitHubClient(owner, repo, token, urlStr string) (GitHub, error) {
	if len(owner) == 0 {
		return nil, errors.New("missing GitHub repository owner")
	}

	if len(repo) == 0 {
		return nil, errors.New("missing GitHub repository name")
	}

	if len(token) == 0 {
		return nil, errors.New("missing GitHub API token")
	}

	if len(urlStr) == 0 {
		return nil, errors.New("missing GitHub API URL")
	}

	baseURL, err := url.ParseRequestURI(urlStr)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse Github API URL")
	}

	ts := oauth2.StaticTokenSource(&oauth2.Token{
		AccessToken: token,
	})
	tc := oauth2.NewClient(context.TODO(), ts)

	client := github.NewClient(tc)
	client.BaseURL = baseURL

	return &GitHubClient{
		Owner:  owner,
		Repo:   repo,
		Client: client,
	}, nil
}

// SetUploadURL constructs the upload URL for a release
func (c *GitHubClient) SetUploadURL(urlStr string) error {
	i := strings.Index(urlStr, "repos/")
	parsedURL, err := url.ParseRequestURI(urlStr[:i])
	if err != nil {
		return errors.Wrap(err, "failed to parse upload URL")
	}

	c.UploadURL = parsedURL
	return nil
}

// CreateRelease creates a new release object in the GitHub API
func (c *GitHubClient) CreateRelease(ctx context.Context, req *github.RepositoryRelease) (*github.RepositoryRelease, error) {

	release, res, err := c.Repositories.CreateRelease(context.TODO(), c.Owner, c.Repo, req)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create a release")
	}

	if res.StatusCode != http.StatusCreated {
		return nil, errors.Errorf("create release: invalid status: %s", res.Status)
	}

	return release, nil
}

// GetRelease queries the GitHub API for a specified release object
func (c *GitHubClient) GetRelease(ctx context.Context, tag string) (*github.RepositoryRelease, error) {
	// Check Release whether already exists or not
	release, res, err := c.Repositories.GetReleaseByTag(context.TODO(), c.Owner, c.Repo, tag)
	if err != nil {
		if res == nil {
			return nil, errors.Wrapf(err, "failed to get release tag: %s", tag)
		}

		// TODO(tcnksm): Handle invalid token
		if res.StatusCode != http.StatusNotFound {
			return nil, errors.Wrapf(err,
				"get release tag: invalid status: %s", res.Status)
		}

		return nil, ErrReleaseNotFound
	}

	return release, nil
}

// EditRelease edit a release object within the GitHub API
func (c *GitHubClient) EditRelease(ctx context.Context, releaseID int64, req *github.RepositoryRelease) (*github.RepositoryRelease, error) {
	var release *github.RepositoryRelease

	err := retry.Retry(3, 3*time.Second, func() error {
		var (
			res *github.Response
			err error
		)
		release, res, err = c.Repositories.EditRelease(context.TODO(), c.Owner, c.Repo, releaseID, req)
		if err != nil {
			return errors.Wrapf(err, "failed to edit release: %d", releaseID)
		}

		if res.StatusCode != http.StatusOK {
			return errors.Errorf("edit release: invalid status: %s", res.Status)
		}
		return nil
	})
	return release, err
}

// DeleteRelease deletes a release object within the GitHub API
func (c *GitHubClient) DeleteRelease(ctx context.Context, releaseID int64) error {
	res, err := c.Repositories.DeleteRelease(context.TODO(), c.Owner, c.Repo, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to delete release")
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete release: invalid status: %s", res.Status)
	}

	return nil
}

// DeleteTag deletes a tag from the GitHub API
func (c *GitHubClient) DeleteTag(ctx context.Context, tag string) error {
	ref := fmt.Sprintf("tags/%s", tag)
	res, err := c.Git.DeleteRef(context.TODO(), c.Owner, c.Repo, ref)
	if err != nil {
		return errors.Wrapf(err, "failed to delete tag: %s", ref)
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete tag: invalid status: %s", res.Status)
	}

	return nil
}

// UploadAsset uploads specified assets to a given release object
func (c *GitHubClient) UploadAsset(ctx context.Context, releaseID int64, filename string) (*github.ReleaseAsset, error) {

	filename, err := filepath.Abs(filename)
	if err != nil {
		return nil, errors.Wrap(err, "failed to get abs path")
	}

	opts := &github.UploadOptions{
		// Use base name by default
		Name: filepath.Base(filename),
	}

	var asset *github.ReleaseAsset
	err = retry.Retry(3, 3*time.Second, func() error {
		var (
			res *github.Response
			err error
		)

		f, err := os.Open(filename)
		if err != nil {
			return errors.Wrap(err, "failed to open file")
		}
		defer f.Close()

		asset, res, err = c.Repositories.UploadReleaseAsset(context.TODO(), c.Owner, c.Repo, releaseID, opts, f)
		if err != nil {
			return errors.Wrapf(err, "failed to upload release asset: %s", filename)
		}

		switch res.StatusCode {
		case http.StatusCreated:
			return nil
		case 422:
			return errors.Errorf(
				"upload release asset: invalid status code: %s",
				"422 (this is probably because the asset already uploaded)")
		default:
			return errors.Errorf(
				"upload release asset: invalid status code: %s", res.Status)
		}
	})
	return asset, err
}

// DeleteAsset deletes assets from a given release object
func (c *GitHubClient) DeleteAsset(ctx context.Context, assetID int64) error {
	res, err := c.Repositories.DeleteReleaseAsset(context.TODO(), c.Owner, c.Repo, assetID)
	if err != nil {
		return errors.Wrap(err, "failed to delete release asset")
	}

	if res.StatusCode != http.StatusNoContent {
		return errors.Errorf("delete release assets: invalid status code: %s", res.Status)
	}

	return nil
}

// ListAssets lists assets associated with a given release
func (c *GitHubClient) ListAssets(ctx context.Context, releaseID int64) ([]*github.ReleaseAsset, error) {
	result := []*github.ReleaseAsset{}
	page := 1

	for {
		assets, res, err := c.Repositories.ListReleaseAssets(context.TODO(), c.Owner, c.Repo, releaseID, &github.ListOptions{Page: page})
		if err != nil {
			return nil, errors.Wrap(err, "failed to list assets")
		}

		if res.StatusCode != http.StatusOK {
			return nil, errors.Errorf("list release assets: invalid status code: %s", res.Status)
		}

		result = append(result, assets...)

		if res.NextPage <= page {
			break
		}

		page = res.NextPage
	}

	return result, nil
}
<|endoftext|>


<commit_before>package goserv

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

// setUp does some setting up for the middleware tests.
func setUp() (*httptest.ResponseRecorder, *http.Request, http.HandlerFunc) {
	recorder := httptest.NewRecorder()
	request, _ := http.NewRequest("GET", "http://127.0.0.1/", nil)
	handler := func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "OK!") }
	return recorder, request, handler
}

func TestRestrictByIP(t *testing.T) {
	// Case 1. Should be blocked
	w, request, handler := setUp()
	wrapped := RestrictByIP(handler, []string{"127.0.0.1"})
	wrapped(w, request)
	if w.Code != 404 {
		t.Fatalf("RestrictByIP did not return a 404: %d, %s", w.Code, w.Body)
	}

	// Case 2: Should be allowed
	w, request, handler = setUp()
	request.RemoteAddr = "127.0.0.1"
	wrapped(w, request)
	if w.Code != 200 {
		t.Fatalf("RestrictByIP did not return a 200: %d, %s", w.Code, w.Body)
	}
}
<commit_msg>middleware tests now reuse a common function.<commit_after>package goserv

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
}

// setUp does some setting up for the middleware tests.
func setUp() (*httptest.ResponseRecorder, *http.Request) {
	recorder := httptest.NewRecorder()
	request, _ := http.NewRequest("GET", "http://127.0.0.1/", nil)
	return recorder, request
}

// restrictedExpectation is reusable code for TestRestrictByIP
func restrictedExpectation(t *testing.T, expectedCode int, allowedIps []string) {
	w, request := setUp()
	wrapped := RestrictByIP(handler, allowedIps)
	request.RemoteAddr = "127.0.0.1"
	wrapped(w, request)
	if w.Code != expectedCode {
		t.Fatalf("RestrictByIP did not return a %d: %d, %s", expectedCode, w.Code, w.Body)
	}
}

func TestRestrictByIP(t *testing.T) {
	// Case 1. Should be blocked due to no IP's in the list
	restrictedExpectation(t, 404, []string{})

	// Case 2: Should be blocked due to ip not in list
	restrictedExpectation(t, 404, []string{"127.0.0.2"})

	// Case 3: Should be allowed
	restrictedExpectation(t, 200, []string{"127.0.0.1"})
}
<|endoftext|>


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

// Gofind searches for Go packages via pkg.go.dev.
//
// Usage:
//      gofind [<flag> ...] <query> ...
//
// Flags
//      -raw   don't apply any formatting if set
package main

import (
	"flag"
	"fmt"
	"go/doc"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func usage() {
	_, _ = fmt.Fprint(os.Stderr, usageDoc)
	os.Exit(2)
}

const usageDoc = `Find Go modules via pkg.go.dev.

Usage:
    gofind [-a] [-raw] query ...

Flags:
    -a     load all search results if set, not just the first 10 results
    -raw   don't apply any formatting if set

Examples:
    gofind logging
    gofind -a logging
    gofind go cloud        # Search for multiple terms
    gofind "go cloud"      # Search for an exact match
    gofind yaml OR json    # Combine searches
`

func main() {
	allFlag := flag.Bool("a", false, "load all search results, not just the first 10 results")
	rawFlag := flag.Bool("raw", false, "don't apply any formatting")

	flag.Usage = usage
	flag.Parse()

	if flag.NArg() == 0 {
		usage()
	}
	args := flag.Args()
	for i, arg := range args {
		if strings.Contains(arg, " ") {
			args[i] = `"` + arg + `"`
		}
	}
	query := strings.Join(args, " ")

	run(query, *allFlag, *rawFlag)
}

func run(query string, all, raw bool) {
	modules, err := search(query, all)
	check(err)
	for _, mod := range modules {
		if raw {
			fmt.Println(mod.modulePath + "\t" + mod.synopsis + "\t" + mod.info)
			continue
		}
		check(mod.writeTo(os.Stdout))
	}
}

func search(query string, all bool) ([]searchResult, error) {
	limit := 10
	if all {
		limit = 100
	}
	return searchLimited(query, limit)
}

func searchLimited(query string, limit int) ([]searchResult, error) {
	v := url.Values{}
	v.Set("q", query)
	v.Set("limit", strconv.Itoa(limit))
	req, err := http.NewRequest("GET", "https://beta.pkg.go.dev/search?"+v.Encode(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", "text/html")

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP status code error: %d %sr", res.StatusCode, res.Status)
	}

	htmlDoc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		return nil, err
	}

	return scrapeSearchResults(htmlDoc)
}

func scrapeSearchResults(htmlDoc *goquery.Document) (sr []searchResult, err error) {
	htmlDoc.Find(".SearchSnippet").Each(func(i int, s *goquery.Selection) {
		header := s.Find(".SearchSnippet-headerContainer").Text()
		moduleName := strings.TrimSpace(header[:strings.Index(header, "(")])
		modulePath := trimParens(strings.TrimSpace(s.Find(".SearchSnippet-header-path").Text()))
		synopsis := strings.TrimSpace(s.Find(".SearchSnippet-synopsis").Text())
		info := formatInfo(s.Find(".SearchSnippet-infoLabel").Text())
		sr = append(sr, searchResult{
			moduleName: moduleName,
			modulePath: modulePath,
			synopsis:   synopsis,
			info:       info,
		})
	})
	return sr, err
}

func trimParens(s string) string {
	return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")")
}

func formatInfo(info string) string {
	var parts []string
	for _, p := range strings.Split(info, "|") {
		parts = append(parts, strings.TrimSpace(p))
	}
	return strings.Join(parts, " | ")
}

type searchResult struct {
	moduleName string
	modulePath string
	synopsis   string
	info       string
}

const (
	punchCardWidth = 80
	indent         = "    "
)

func (s searchResult) writeTo(w io.Writer) error {
	_, err := fmt.Fprintf(w, "%s (%s)\n", s.moduleName, s.modulePath)
	if err != nil {
		return err
	}
	if s.synopsis != "" {
		doc.ToText(w, s.synopsis, indent, "", punchCardWidth-2*len(indent))
	}
	_, err = fmt.Fprintf(w, "\n%s%s\n\n", indent, s.info)
	return err
}

func check(err error) {
	if err != nil {
		fail(err)
	}
}

func fail(msg ...interface{}) {
	_, _ = fmt.Fprintln(os.Stderr, msg...)
	os.Exit(1)
}
<commit_msg>change beta.pkg.go.dev to pkg.go.dev<commit_after>// Copyright 2013 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Gofind searches for Go packages via pkg.go.dev.
//
// Usage:
//      gofind [<flag> ...] <query> ...
//
// Flags
//      -raw   don't apply any formatting if set
package main

import (
	"flag"
	"fmt"
	"go/doc"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func usage() {
	_, _ = fmt.Fprint(os.Stderr, usageDoc)
	os.Exit(2)
}

const usageDoc = `Find Go modules via pkg.go.dev.

Usage:
    gofind [-a] [-raw] query ...

Flags:
    -a     load all search results if set, not just the first 10 results
    -raw   don't apply any formatting if set

Examples:
    gofind logging
    gofind -a logging
    gofind go cloud        # Search for multiple terms
    gofind "go cloud"      # Search for an exact match
    gofind yaml OR json    # Combine searches
`

func main() {
	allFlag := flag.Bool("a", false, "load all search results, not just the first 10 results")
	rawFlag := flag.Bool("raw", false, "don't apply any formatting")

	flag.Usage = usage
	flag.Parse()

	if flag.NArg() == 0 {
		usage()
	}
	args := flag.Args()
	for i, arg := range args {
		if strings.Contains(arg, " ") {
			args[i] = `"` + arg + `"`
		}
	}
	query := strings.Join(args, " ")

	run(query, *allFlag, *rawFlag)
}

func run(query string, all, raw bool) {
	modules, err := search(query, all)
	check(err)
	for _, mod := range modules {
		if raw {
			fmt.Println(mod.modulePath + "\t" + mod.synopsis + "\t" + mod.info)
			continue
		}
		check(mod.writeTo(os.Stdout))
	}
}

func search(query string, all bool) ([]searchResult, error) {
	limit := 10
	if all {
		limit = 100
	}
	return searchLimited(query, limit)
}

func searchLimited(query string, limit int) ([]searchResult, error) {
	v := url.Values{}
	v.Set("q", query)
	v.Set("limit", strconv.Itoa(limit))
	req, err := http.NewRequest("GET", "https://pkg.go.dev/search?"+v.Encode(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", "text/html")

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP status code error: %d %sr", res.StatusCode, res.Status)
	}

	htmlDoc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		return nil, err
	}

	return scrapeSearchResults(htmlDoc)
}

func scrapeSearchResults(htmlDoc *goquery.Document) (sr []searchResult, err error) {
	htmlDoc.Find(".SearchSnippet").Each(func(i int, s *goquery.Selection) {
		header := s.Find(".SearchSnippet-headerContainer").Text()
		moduleName := strings.TrimSpace(header[:strings.Index(header, "(")])
		modulePath := trimParens(strings.TrimSpace(s.Find(".SearchSnippet-header-path").Text()))
		synopsis := strings.TrimSpace(s.Find(".SearchSnippet-synopsis").Text())
		info := formatInfo(s.Find(".SearchSnippet-infoLabel").Text())
		sr = append(sr, searchResult{
			moduleName: moduleName,
			modulePath: modulePath,
			synopsis:   synopsis,
			info:       info,
		})
	})
	return sr, err
}

func trimParens(s string) string {
	return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")")
}

func formatInfo(info string) string {
	var parts []string
	for _, p := range strings.Split(info, "|") {
		parts = append(parts, strings.TrimSpace(p))
	}
	return strings.Join(parts, " | ")
}

type searchResult struct {
	moduleName string
	modulePath string
	synopsis   string
	info       string
}

const (
	punchCardWidth = 80
	indent         = "    "
)

func (s searchResult) writeTo(w io.Writer) error {
	_, err := fmt.Fprintf(w, "%s (%s)\n", s.moduleName, s.modulePath)
	if err != nil {
		return err
	}
	if s.synopsis != "" {
		doc.ToText(w, s.synopsis, indent, "", punchCardWidth-2*len(indent))
	}
	_, err = fmt.Fprintf(w, "\n%s%s\n\n", indent, s.info)
	return err
}

func check(err error) {
	if err != nil {
		fail(err)
	}
}

func fail(msg ...interface{}) {
	_, _ = fmt.Fprintln(os.Stderr, msg...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>// A simple LLRP-based logical reader mock for RFID Tags using go-llrp
package main

import (
	"encoding/binary"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/gin-gonic/contrib/static"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/iomz/go-llrp"
	"github.com/juju/loggo"
	"golang.org/x/net/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
)

// ManagementAction is a type for TagManager
type ManagementAction int

const (
	// RetrieveTags is a const for retrieving tags
	RetrieveTags ManagementAction = iota
	// AddTags is a const for adding tags
	AddTags
	// DeleteTags is a const for deleting tags
	DeleteTags
)

// TagManager is a struct for tag management channel
type TagManager struct {
	action ManagementAction
	tags   []*Tag
}

// Constant values
const (
	// BufferSize is a general size for a buffer
	BufferSize = 512
)

var (
	// Current Version
	version = "0.1.0"

	// kingpin app
	app = kingpin.New("golemu", "A mock LLRP-based logical reader emulator for RFID Tags.")
	// kingpin debug mode flag
	debug = app.Flag("debug", "Enable debug mode.").Short('v').Default("false").Bool()
	// kingpin initial MessageID
	initialMessageID = app.Flag("initialMessageID", "The initial messageID to start from.").Short('m').Default("1000").Int()
	// kingpin initial KeepaliveID
	initialKeepaliveID = app.Flag("initialKeepaliveID", "The initial keepaliveID to start from.").Short('k').Default("80000").Int()
	// kingpin LLRP listening port
	port = app.Flag("port", "LLRP listening port.").Short('p').Default("5084").Int()
	// kingpin LLRP listening IP address
	ip = app.Flag("ip", "LLRP listening address.").Short('a').Default("0.0.0.0").IP()

	// kingpin server command
	server = app.Command("server", "Run as a tag stream server.")
	// kingpin report interval
	reportInterval = server.Flag("reportInterval", "The interval of ROAccessReport in ms. Pseudo ROReport spec option.").Short('i').Default("1000").Int()
	// kingpin maximum tag to include in ROAccessReport
	maxTag = server.Flag("maxTag", "The maximum number of TagReportData parameters per ROAccessReport. Pseudo ROReport spec option. 0 for no limit.").Short('t').Default("0").Int()
	// kingpin tag list file
	file = server.Flag("file", "The file containing Tag data.").Short('f').Default("tags.csv").String()
	// kingpin web port
	webPort = server.Flag("webPort", "Port listening for web access.").Short('w').Default("3000").Int()

	// kingpin client command
	client = app.Command("client", "Run as a client mode.")

	// loggo
	logger = loggo.GetLogger("")

	// LLRPConn flag
	isLLRPConnAlive = false
	// Current messageID
	messageID = uint32(*initialMessageID)
	// Current KeepaliveID
	keepaliveID = *initialKeepaliveID
	// Current activeClients
	activeClients = make(map[WebsockConn]int) // map containing clients
	// Tag management channel
	tagManager = make(chan *TagManager)
	// notify tag update channel
	notify = make(chan bool)
	// update TagReportDataStack when tag is updated
	tagUpdated = make(chan []*Tag)
)

func init() {
}

// Iterate through the Tags and write ROAccessReport message to the socket
func sendROAccessReport(conn net.Conn, trds *TagReportDataStack) error {
	for _, trd := range trds.Stack {
		// Append TagReportData to ROAccessReport
		roar := llrp.ROAccessReport(trd.Parameter, messageID)
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()

		// Send
		_, err := conn.Write(roar)
		if err != nil {
			return err
		}

		// Wait until ACK received
		time.Sleep(time.Millisecond)
	}

	return nil
}

// Handles incoming requests.
func handleRequest(conn net.Conn, tags []*Tag) {
	// Make a buffer to hold incoming data.
	buf := make([]byte, BufferSize)
	trds := buildTagReportDataStack(tags)

	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			logger.Infof("The client is disconnected, closing LLRP connection")
			conn.Close()
			return
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Infof("Closing LLRP connection")
			conn.Close()
			return
		}

		// Respond according to the LLRP packet header
		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.SetReaderConfigHeader || header == llrp.KeepaliveAckHeader {
			if header == llrp.SetReaderConfigHeader {
				// SRC received, start ROAR
				logger.Infof(">>> SET_READER_CONFIG")
				conn.Write(llrp.SetReaderConfigResponse())
			} else if header == llrp.KeepaliveAckHeader {
				// KA receieved, continue ROAR
				logger.Infof(">>> KeepaliveAck")
			}
			// Tick ROAR and Keepalive interval
			roarTicker := time.NewTicker(time.Duration(*reportInterval) * time.Millisecond)
			keepaliveTicker := time.NewTicker(10 * time.Second)
			for { // Infinite loop
				isLLRPConnAlive = true
				logger.Debugf("[LLRP handler select]: %v", trds)
				select {
				// ROAccessReport interval tick
				case <-roarTicker.C:
					logger.Tracef("### roarTicker.C")
					logger.Infof("<<< ROAccessReport (# of Tags: %v, # of TagReportData: %v)", trds.TotalTagCounts(), len(trds.Stack))
					err := sendROAccessReport(conn, trds)
					if err != nil {
						logger.Errorf(err.Error())
						isLLRPConnAlive = false
					}
				// Keepalive interval tick
				case <-keepaliveTicker.C:
					logger.Tracef("### keepaliveTicker.C")
					logger.Infof("<<< Keepalive")
					conn.Write(llrp.Keepalive())
					isLLRPConnAlive = false
				// When the tag queue is updated
				case tags := <-tagUpdated:
					logger.Tracef("### TagUpdated")
					trds = buildTagReportDataStack(tags)
				}
				if !isLLRPConnAlive {
					roarTicker.Stop()
					keepaliveTicker.Stop()
					break
				}
			}
		} else {
			// Unknown LLRP packet received, reset the connection
			logger.Warningf("Unknown header: %v, reqlen: %v", header, reqLen)
			logger.Warningf("Message: %v", buf)
			return
		}
	}
}

// APIPostTag redirects the tag addition request
func APIPostTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqAddTag("add", json); res == "error" {
		c.String(http.StatusAlreadyReported, "The tag already exists!\n")
	} else {
		c.String(http.StatusAccepted, "Post requested!\n")
	}
}

// APIDeleteTag redirects the tag deletion request
func APIDeleteTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqDeleteTag("delete", json); res == "error" {
		c.String(http.StatusNoContent, "The tag doesn't exist!\n")
	} else {
		c.String(http.StatusAccepted, "Delete requested!\n")
	}
}

// server mode
func runServer() int {
	// Read virtual tags from a csv file
	logger.Infof("Loading virtual Tags from \"%v\"", *file)

	if _, err := os.Stat(*file); os.IsNotExist(err) {
		_, err := os.Create(*file)
		check(err)
		logger.Infof("%v created.", *file)
	}

	csvIn, err := ioutil.ReadFile(*file)
	check(err)
	tags := loadTagsFromCSV(string(csvIn))

	// Listen for incoming connections.
	l, err := net.Listen("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	// Close the listener when the application closes.
	defer l.Close()
	logger.Infof("Listening on %v:%v", ip, *port)

	// Channel for communicating virtual tag updates and signals
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	// Handle websocket and static file hosting with gin
	go func() {
		r := gin.Default()
		r.Use(static.Serve("/", static.LocalFile("./public", true)))
		r.GET("/ws", func(c *gin.Context) {
			handler := websocket.Handler(SockServer)
			handler.ServeHTTP(c.Writer, c.Request)
		})
		v1 := r.Group("api/v1")
		v1.POST("/tags", APIPostTag)
		v1.DELETE("/tags", APIDeleteTag)
		r.Run(":" + strconv.Itoa(*webPort))
	}()

	go func() {
		for {
			select {
			case cmd := <-tagManager:
				// Tag management
				res := []*Tag{}
				switch cmd.action {
				case AddTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i < 0 {
							tags = append(tags, t)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case DeleteTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i >= 0 {
							tags = append(tags[:i], tags[i+1:]...)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case RetrieveTags:
					res = tags
				}
				cmd.tags = res
				tagManager <- cmd
			case signal := <-signals:
				// Handle SIGINT and SIGTERM.
				logger.Infof("%v", signal)
				os.Exit(0)
			}
		}
	}()

	// Handle LLRP connection
	for {
		// Accept an incoming connection.
		logger.Infof("LLRP connection initiated")
		conn, err := l.Accept()
		if err != nil {
			logger.Errorf(err.Error())
			os.Exit(2)
		}

		// Send back READER_EVENT_NOTIFICATION
		currentTime := uint64(time.Now().UTC().Nanosecond() / 1000)
		conn.Write(llrp.ReaderEventNotification(messageID, currentTime))
		logger.Infof("<<< READER_EVENT_NOTIFICATION")
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		time.Sleep(time.Millisecond)

		// Handle connections in a new goroutine.
		go handleRequest(conn, tags)
	}
}

// client mode
func runClient() int {
	// Establish a connection to the llrp client
	conn, err := net.Dial("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	buf := make([]byte, BufferSize)
	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			return 0
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Errorf("reqLen = %v", reqLen)
			conn.Close()
			break
		}

		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.ReaderEventNotificationHeader {
			logger.Infof(">>> READER_EVENT_NOTIFICATION")
			conn.Write(llrp.SetReaderConfig(messageID))
		} else if header == llrp.SetReaderConfigResponseHeader {
			logger.Infof(">>> SET_READER_CONFIG_RESPONSE")
		} else if header == llrp.ROAccessReportHeader {
			logger.Infof(">>> RO_ACCESS_REPORT")
			logger.Debugf("Packet size: %v\n", reqLen)
			logger.Debugf("% x\n", buf[:reqLen])
		} else {
			logger.Warningf("Unknown header: %v\n", header)
		}
	}
	return 0
}

func main() {
	app.Version(version)
	parse := kingpin.MustParse(app.Parse(os.Args[1:]))

	if *debug {
		loggo.ConfigureLoggers("TRACE")
		gin.SetMode(gin.DebugMode)
	} else {
		loggo.ConfigureLoggers("INFO")
		gin.SetMode(gin.ReleaseMode)
	}

	switch parse {
	case server.FullCommand():
		os.Exit(runServer())
	case client.FullCommand():
		os.Exit(runClient())
	}
}
<commit_msg>add KeepaliveAck response in client mode<commit_after>// A simple LLRP-based logical reader mock for RFID Tags using go-llrp
package main

import (
	"encoding/binary"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/gin-gonic/contrib/static"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/iomz/go-llrp"
	"github.com/juju/loggo"
	"golang.org/x/net/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
)

// ManagementAction is a type for TagManager
type ManagementAction int

const (
	// RetrieveTags is a const for retrieving tags
	RetrieveTags ManagementAction = iota
	// AddTags is a const for adding tags
	AddTags
	// DeleteTags is a const for deleting tags
	DeleteTags
)

// TagManager is a struct for tag management channel
type TagManager struct {
	action ManagementAction
	tags   []*Tag
}

// Constant values
const (
	// BufferSize is a general size for a buffer
	BufferSize = 512
)

var (
	// Current Version
	version = "0.1.0"

	// kingpin app
	app = kingpin.New("golemu", "A mock LLRP-based logical reader emulator for RFID Tags.")
	// kingpin debug mode flag
	debug = app.Flag("debug", "Enable debug mode.").Short('v').Default("false").Bool()
	// kingpin initial MessageID
	initialMessageID = app.Flag("initialMessageID", "The initial messageID to start from.").Short('m').Default("1000").Int()
	// kingpin initial KeepaliveID
	initialKeepaliveID = app.Flag("initialKeepaliveID", "The initial keepaliveID to start from.").Short('k').Default("80000").Int()
	// kingpin LLRP listening port
	port = app.Flag("port", "LLRP listening port.").Short('p').Default("5084").Int()
	// kingpin LLRP listening IP address
	ip = app.Flag("ip", "LLRP listening address.").Short('a').Default("0.0.0.0").IP()

	// kingpin server command
	server = app.Command("server", "Run as a tag stream server.")
	// kingpin report interval
	reportInterval = server.Flag("reportInterval", "The interval of ROAccessReport in ms. Pseudo ROReport spec option.").Short('i').Default("1000").Int()
	// kingpin maximum tag to include in ROAccessReport
	maxTag = server.Flag("maxTag", "The maximum number of TagReportData parameters per ROAccessReport. Pseudo ROReport spec option. 0 for no limit.").Short('t').Default("0").Int()
	// kingpin tag list file
	file = server.Flag("file", "The file containing Tag data.").Short('f').Default("tags.csv").String()
	// kingpin web port
	webPort = server.Flag("webPort", "Port listening for web access.").Short('w').Default("3000").Int()

	// kingpin client command
	client = app.Command("client", "Run as a client mode.")

	// loggo
	logger = loggo.GetLogger("")

	// LLRPConn flag
	isLLRPConnAlive = false
	// Current messageID
	messageID = uint32(*initialMessageID)
	// Current KeepaliveID
	keepaliveID = *initialKeepaliveID
	// Current activeClients
	activeClients = make(map[WebsockConn]int) // map containing clients
	// Tag management channel
	tagManager = make(chan *TagManager)
	// notify tag update channel
	notify = make(chan bool)
	// update TagReportDataStack when tag is updated
	tagUpdated = make(chan []*Tag)
)

func init() {
}

// Iterate through the Tags and write ROAccessReport message to the socket
func sendROAccessReport(conn net.Conn, trds *TagReportDataStack) error {
	for _, trd := range trds.Stack {
		// Append TagReportData to ROAccessReport
		roar := llrp.ROAccessReport(trd.Parameter, messageID)
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		logger.Infof("%v\n", len(roar))

		// Send
		_, err := conn.Write(roar)
		if err != nil {
			return err
		}

		// Wait until ACK received
		time.Sleep(time.Millisecond)
	}

	return nil
}

// Handles incoming requests.
func handleRequest(conn net.Conn, tags []*Tag) {
	// Make a buffer to hold incoming data.
	buf := make([]byte, BufferSize)
	trds := buildTagReportDataStack(tags)

	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			logger.Infof("The client is disconnected, closing LLRP connection")
			conn.Close()
			return
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Infof("Closing LLRP connection")
			conn.Close()
			return
		}

		// Respond according to the LLRP packet header
		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.SetReaderConfigHeader || header == llrp.KeepaliveAckHeader {
			if header == llrp.SetReaderConfigHeader {
				// SRC received, start ROAR
				logger.Infof(">>> SET_READER_CONFIG")
				conn.Write(llrp.SetReaderConfigResponse())
			} else if header == llrp.KeepaliveAckHeader {
				// KA receieved, continue ROAR
				logger.Infof(">>> KeepaliveAck")
			}
			// Tick ROAR and Keepalive interval
			roarTicker := time.NewTicker(time.Duration(*reportInterval) * time.Millisecond)
			keepaliveTicker := time.NewTicker(10 * time.Second)
			for { // Infinite loop
				isLLRPConnAlive = true
				logger.Debugf("[LLRP handler select]: %v", trds)
				select {
				// ROAccessReport interval tick
				case <-roarTicker.C:
					logger.Tracef("### roarTicker.C")
					logger.Infof("<<< ROAccessReport (# of Tags: %v, # of TagReportData: %v)", trds.TotalTagCounts(), len(trds.Stack))
					err := sendROAccessReport(conn, trds)
					if err != nil {
						logger.Errorf(err.Error())
						isLLRPConnAlive = false
					}
				// Keepalive interval tick
				case <-keepaliveTicker.C:
					logger.Tracef("### keepaliveTicker.C")
					logger.Infof("<<< Keepalive")
					conn.Write(llrp.Keepalive())
					isLLRPConnAlive = false
				// When the tag queue is updated
				case tags := <-tagUpdated:
					logger.Tracef("### TagUpdated")
					trds = buildTagReportDataStack(tags)
				}
				if !isLLRPConnAlive {
					roarTicker.Stop()
					keepaliveTicker.Stop()
					break
				}
			}
		} else {
			// Unknown LLRP packet received, reset the connection
			logger.Warningf("Unknown header: %v, reqlen: %v", header, reqLen)
			logger.Warningf("Message: %v", buf)
			return
		}
	}
}

// APIPostTag redirects the tag addition request
func APIPostTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqAddTag("add", json); res == "error" {
		c.String(http.StatusAlreadyReported, "The tag already exists!\n")
	} else {
		c.String(http.StatusAccepted, "Post requested!\n")
	}
}

// APIDeleteTag redirects the tag deletion request
func APIDeleteTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqDeleteTag("delete", json); res == "error" {
		c.String(http.StatusNoContent, "The tag doesn't exist!\n")
	} else {
		c.String(http.StatusAccepted, "Delete requested!\n")
	}
}

// server mode
func runServer() int {
	// Read virtual tags from a csv file
	logger.Infof("Loading virtual Tags from \"%v\"", *file)

	if _, err := os.Stat(*file); os.IsNotExist(err) {
		_, err := os.Create(*file)
		check(err)
		logger.Infof("%v created.", *file)
	}

	csvIn, err := ioutil.ReadFile(*file)
	check(err)
	tags := loadTagsFromCSV(string(csvIn))

	// Listen for incoming connections.
	l, err := net.Listen("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	// Close the listener when the application closes.
	defer l.Close()
	logger.Infof("Listening on %v:%v", ip, *port)

	// Channel for communicating virtual tag updates and signals
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	// Handle websocket and static file hosting with gin
	go func() {
		r := gin.Default()
		r.Use(static.Serve("/", static.LocalFile("./public", true)))
		r.GET("/ws", func(c *gin.Context) {
			handler := websocket.Handler(SockServer)
			handler.ServeHTTP(c.Writer, c.Request)
		})
		v1 := r.Group("api/v1")
		v1.POST("/tags", APIPostTag)
		v1.DELETE("/tags", APIDeleteTag)
		r.Run(":" + strconv.Itoa(*webPort))
	}()

	go func() {
		for {
			select {
			case cmd := <-tagManager:
				// Tag management
				res := []*Tag{}
				switch cmd.action {
				case AddTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i < 0 {
							tags = append(tags, t)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case DeleteTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i >= 0 {
							tags = append(tags[:i], tags[i+1:]...)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case RetrieveTags:
					res = tags
				}
				cmd.tags = res
				tagManager <- cmd
			case signal := <-signals:
				// Handle SIGINT and SIGTERM.
				logger.Infof("%v", signal)
				os.Exit(0)
			}
		}
	}()

	// Handle LLRP connection
	for {
		// Accept an incoming connection.
		logger.Infof("LLRP connection initiated")
		conn, err := l.Accept()
		if err != nil {
			logger.Errorf(err.Error())
			os.Exit(2)
		}

		// Send back READER_EVENT_NOTIFICATION
		currentTime := uint64(time.Now().UTC().Nanosecond() / 1000)
		conn.Write(llrp.ReaderEventNotification(messageID, currentTime))
		logger.Infof("<<< READER_EVENT_NOTIFICATION")
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		time.Sleep(time.Millisecond)

		// Handle connections in a new goroutine.
		go handleRequest(conn, tags)
	}
}

// client mode
func runClient() int {
	// Establish a connection to the llrp client
	conn, err := net.Dial("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	buf := make([]byte, BufferSize)
	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			return 0
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Errorf("reqLen = %v", reqLen)
			conn.Close()
			break
		}

		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.ReaderEventNotificationHeader {
			logger.Infof(">>> READER_EVENT_NOTIFICATION")
			conn.Write(llrp.SetReaderConfig(messageID))
		} else if header == llrp.KeepaliveHeader {
			logger.Infof(">>> KEEP_ALIVE")
			conn.Write(llrp.KeepaliveAck())
		} else if header == llrp.SetReaderConfigResponseHeader {
			logger.Infof(">>> SET_READER_CONFIG_RESPONSE")
		} else if header == llrp.ROAccessReportHeader {
			logger.Infof(">>> RO_ACCESS_REPORT")
			logger.Debugf("Packet size: %v\n", reqLen)
			logger.Debugf("% x\n", buf[:reqLen])
		} else {
			logger.Warningf("Unknown header: %v\n", header)
		}
	}
	return 0
}

func main() {
	app.Version(version)
	parse := kingpin.MustParse(app.Parse(os.Args[1:]))

	if *debug {
		loggo.ConfigureLoggers("TRACE")
		gin.SetMode(gin.DebugMode)
	} else {
		loggo.ConfigureLoggers("INFO")
		gin.SetMode(gin.ReleaseMode)
	}

	switch parse {
	case server.FullCommand():
		os.Exit(runServer())
	case client.FullCommand():
		os.Exit(runClient())
	}
}
<|endoftext|>


<commit_before>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "github.com/mrshu/go-notetxt"
        "flag"
        "os/user"
        "time"
        "os"
        "io/ioutil"
        "os/exec"
        "strings"
)

func main() {

        conf, _ := globalconf.New("gonote")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 && !today {
                        fmt.Println("I need something to add.")
                        return
                }

                if today {
                        t := time.Now().Local()
                        dir := fmt.Sprintf("%s/%s", *flagNotedir, t.Format("2006/01/"))
                        os.MkdirAll(dir, 755)

                        text := fmt.Sprintf("Daily journal, date %s", t.Format("02. 01. 2006"))
                        spacer := "\n" + strings.Repeat("=", len(text))
                        file := fmt.Sprintf("%s%s.rst", dir, notetxt.TitleToFilename(text))

                        if _, err := os.Stat(file); err == nil {
                                fmt.Println("gonote: Notefile for today already exists. " +
                                                "You can still edit it if you want.")
                                return
                        }

                        e := ioutil.WriteFile(file,
                                                []byte(text + spacer),
                                                0644)
                        if e != nil {
                                panic(e)
                        }

                        editor := os.Getenv("EDITOR")
                        if len(editor) == 0 {
                                editor = "nano" //FIXME: saner default?
                        }

                        c := exec.Command(editor, file)

                        // nasty hack, see http://stackoverflow.com/a/12089980
                        c.Stdin = os.Stdin
                        c.Stdout = os.Stdout
                        c.Stderr = os.Stderr

                        er := c.Run()

                        if er != nil {
                                fmt.Println(er.Error())
                                panic(er)
                        }
                }
            },
        }
        cmdAdd.Flags().BoolVarP(&today, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "list",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                for i, note := range notes {
                    fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                }
            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonote",
            Short: "gonote is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.Execute()
}
<commit_msg>refactoring: Putting repeating code to funcitons<commit_after>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "github.com/mrshu/go-notetxt"
        "flag"
        "os/user"
        "time"
        "os"
        "io/ioutil"
        "os/exec"
        "strings"
)

func openFileInEditor(file string) {
        editor := os.Getenv("EDITOR")
        if len(editor) == 0 {
                editor = "nano" //FIXME: saner default?
        }

        c := exec.Command(editor, file)

        // nasty hack, see http://stackoverflow.com/a/12089980
        c.Stdin = os.Stdin
        c.Stdout = os.Stdout
        c.Stderr = os.Stderr

        er := c.Run()

        if er != nil {
                fmt.Println(er.Error())
                panic(er)
        }
}

func main() {

        conf, _ := globalconf.New("gonote")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 && !today {
                        fmt.Println("I need something to add.")
                        return
                }

                if today {
                        t := time.Now().Local()
                        dir := fmt.Sprintf("%s/%s", *flagNotedir, t.Format("2006/01/"))
                        os.MkdirAll(dir, 755)

                        text := fmt.Sprintf("Daily journal, date %s", t.Format("02. 01. 2006"))
                        spacer := "\n" + strings.Repeat("=", len(text))
                        file := fmt.Sprintf("%s%s.rst", dir, notetxt.TitleToFilename(text))

                        if _, err := os.Stat(file); err == nil {
                                fmt.Println("gonote: Notefile for today already exists. " +
                                                "You can still edit it if you want.")
                                return
                        }

                        e := ioutil.WriteFile(file,
                                                []byte(text + spacer),
                                                0644)
                        if e != nil {
                                panic(e)
                        }

                        openFileInEditor(file)
                }
            },
        }
        cmdAdd.Flags().BoolVarP(&today, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "list",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                for i, note := range notes {
                    fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                }
            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonote",
            Short: "gonote is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.Execute()
}
<|endoftext|>


<commit_before>package gopush

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type Instruction func(map[string]*Stack)

type Stack struct {
	Stack     []interface{}
	Functions map[string]Instruction
}

func (s Stack) Peek() interface{} {
	if len(s.Stack) == 0 {
		return struct{}{}
	}

	return s.Stack[len(s.Stack)-1]
}

func (s *Stack) Push(lit interface{}) {
	s.Stack = append(s.Stack, lit)
}

func (s *Stack) Pop() (item interface{}) {
	if len(s.Stack) == 0 {
		return struct{}{}
	}

	item = s.Stack[len(s.Stack)-1]
	s.Stack = s.Stack[:len(s.Stack)-1]

	return item
}

func (s Stack) Len() int {
	return len(s.Stack)
}

func NewIntStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["+"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i1 + i2)
	}

	s.Functions["-"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i2 - i1)
	}

	s.Functions["*"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i1 * i2)
	}

	return s
}

func NewFloatStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["+"] = func(stacks map[string]*Stack) {
		if stacks["float"].Len() < 2 {
			return
		}

		f1 := stacks["float"].Pop().(float64)
		f2 := stacks["float"].Pop().(float64)
		stacks["float"].Push(f1 + f2)
	}

	s.Functions["*"] = func(stacks map[string]*Stack) {
		if stacks["float"].Len() < 2 {
			return
		}

		f1 := stacks["float"].Pop().(float64)
		f2 := stacks["float"].Pop().(float64)
		stacks["float"].Push(f1 * f2)
	}

	return s
}

func NewBooleanStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["or"] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() < 2 {
			return
		}

		b1 := stacks["boolean"].Pop().(bool)
		b2 := stacks["boolean"].Pop().(bool)
		stacks["boolean"].Push(b1 || b2)
	}

	return s
}

type Options struct {
}

type Interpreter struct {
	Stacks map[string]*Stack
}

var DefaultOptions = Options{}

func NewInterpreter(options Options) *Interpreter {
	interpreter := &Interpreter{
		Stacks: make(map[string]*Stack),
	}

	interpreter.Stacks["integer"] = NewIntStack(options)
	interpreter.Stacks["float"] = NewFloatStack(options)
	interpreter.Stacks["exec"] = new(Stack)
	interpreter.Stacks["boolean"] = NewBooleanStack(options)

	return interpreter
}

func ignoreWhiteSpace(program string) string {
	for i, r := range program {
		if !unicode.IsSpace(r) {
			return program[i:]
		}
	}
	return ""
}

func getToken(program string) (token, remainder string) {
	for i, r := range program {
		if unicode.IsSpace(r) {
			return program[:i], program[i:]
		}
	}
	return program, ""
}

func getToParen(program string) (subprogram, remainder string, err error) {
	parenBalance := 1
	for i, r := range program {
		switch r {
		case '(':
			parenBalance++
		case ')':
			parenBalance--
		}

		if parenBalance == 0 {
			return program[:i], program[i+1:], nil
		}
	}
	return "", "", errors.New("unmatched parentheses")
}

func splitProgram(program string) (result []string, err error) {
	var p, t string

	p = program
	for len(p) > 0 {
		p = ignoreWhiteSpace(p)
		t, p = getToken(p)

		if t == "" {
			continue
		}

		if t == "(" {
			t, p, err = getToParen(p)
			if err != nil {
				return []string{}, err
			}
		}

		result = append(result, t)
	}

	return result, nil
}

func (i *Interpreter) Run(program string) (err error) {
	i.Stacks["exec"].Push(strings.TrimSpace(program))

	for i.Stacks["exec"].Len() > 0 {
		item := i.Stacks["exec"].Pop().(string)

		// If the item on top of the exec stack is a list, push it in
		// reverse order
		if strings.Contains(item, " ") {
			p, err := splitProgram(item)
			if err != nil {
				return err
			}
			for j := len(p) - 1; j >= 0; j-- {
				i.Stacks["exec"].Push(p[j])
			}
			continue
		}

		// Try to parse the item on top of the exec stack as a literal
		if intlit, err := strconv.ParseInt(item, 10, 64); err == nil {
			i.Stacks["integer"].Push(intlit)
			continue
		}

		if floatlit, err := strconv.ParseFloat(item, 64); err == nil {
			i.Stacks["float"].Push(floatlit)
			continue
		}

		if boollit, err := strconv.ParseBool(item); err == nil {
			i.Stacks["boolean"].Push(boollit)
			continue
		}

		// Try to parse the item on top of the exec stack as instruction
		item = strings.ToLower(item)
		if strings.Contains(item, ".") {
			stack := item[:strings.Index(item, ".")]
			operation := item[strings.Index(item, ".")+1:]

			s, ok := i.Stacks[stack]
			if !ok {
				return errors.New(fmt.Sprintf("unkown stack: %v", stack))
			}

			f, ok := s.Functions[operation]
			if !ok {
				return errors.New(fmt.Sprintf("unknown instruction: %v.%v", stack, operation))
			}

			f(i.Stacks)
			continue
		}

		return errors.New(fmt.Sprintf("not an instruction: %q", item))
	}

	return nil
}
<commit_msg>Implement the instructions for the boolean stack<commit_after>package gopush

import (
	"errors"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"unicode"
)

type Instruction func(map[string]*Stack)

type Stack struct {
	Stack     []interface{}
	Functions map[string]Instruction
}

func (s Stack) Peek() interface{} {
	if len(s.Stack) == 0 {
		return struct{}{}
	}

	return s.Stack[len(s.Stack)-1]
}

func (s *Stack) Push(lit interface{}) {
	s.Stack = append(s.Stack, lit)
}

func (s *Stack) Pop() (item interface{}) {
	if len(s.Stack) == 0 {
		return struct{}{}
	}

	item = s.Stack[len(s.Stack)-1]
	s.Stack = s.Stack[:len(s.Stack)-1]

	return item
}

func (s Stack) Len() int64 {
	return int64(len(s.Stack))
}

func (s *Stack) Dup() {
	if len(s.Stack) == 0 {
		return
	}

	s.Push(s.Peek())
}

func (s *Stack) Swap() {
	if len(s.Stack) < 2 {
		return
	}

	i1 := s.Pop()
	i2 := s.Pop()
	s.Push(i1)
	s.Push(i2)
}

func (s *Stack) Flush() {
	s.Stack = nil
}

func (s *Stack) Rot() {
	if len(s.Stack) < 3 {
		return
	}

	i1 := s.Pop()
	i2 := s.Pop()
	i3 := s.Pop()

	s.Push(i2)
	s.Push(i1)
	s.Push(i3)
}

func (s *Stack) Shove(item interface{}, idx int64) {
	//TODO
}

func (s *Stack) Yank(idx int64) {
	// TODO
}

func (s *Stack) YankDup(idx int64) {
	// TODO
}

func NewIntStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["+"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i1 + i2)
	}

	s.Functions["-"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i2 - i1)
	}

	s.Functions["*"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() < 2 {
			return
		}

		i1 := stacks["integer"].Pop().(int64)
		i2 := stacks["integer"].Pop().(int64)
		stacks["integer"].Push(i1 * i2)
	}

	return s
}

func NewFloatStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["+"] = func(stacks map[string]*Stack) {
		if stacks["float"].Len() < 2 {
			return
		}

		f1 := stacks["float"].Pop().(float64)
		f2 := stacks["float"].Pop().(float64)
		stacks["float"].Push(f1 + f2)
	}

	s.Functions["*"] = func(stacks map[string]*Stack) {
		if stacks["float"].Len() < 2 {
			return
		}

		f1 := stacks["float"].Pop().(float64)
		f2 := stacks["float"].Pop().(float64)
		stacks["float"].Push(f1 * f2)
	}

	return s
}

func NewBooleanStack(options Options) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["="] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() < 2 {
			return
		}

		b1 := stacks["boolean"].Pop().(bool)
		b2 := stacks["boolean"].Pop().(bool)
		stacks["boolean"].Push(b1 == b2)
	}

	s.Functions["and"] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() < 2 {
			return
		}

		b1 := stacks["boolean"].Pop().(bool)
		b2 := stacks["boolean"].Pop().(bool)
		stacks["boolean"].Push(b1 && b2)
	}

	s.Functions["define"] = func(stacks map[string]*Stack) {
		// TODO
		return
	}

	s.Functions["dup"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Dup()
	}

	s.Functions["flush"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Flush()
	}

	s.Functions["fromfloat"] = func(stacks map[string]*Stack) {
		if stacks["float"].Len() == 0 {
			return
		}

		f := stacks["float"].Pop().(float64)
		stacks["boolean"].Push(f != 0)
	}

	s.Functions["frominteger"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() == 0 {
			return
		}

		i := stacks["integer"].Pop().(int64)
		stacks["boolean"].Push(i != 0)
	}

	s.Functions["not"] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() == 0 {
			return
		}

		b := stacks["boolean"].Pop().(bool)
		stacks["boolean"].Push(!b)
	}

	s.Functions["or"] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() < 2 {
			return
		}

		b1 := stacks["boolean"].Pop().(bool)
		b2 := stacks["boolean"].Pop().(bool)
		stacks["boolean"].Push(b1 || b2)
	}

	s.Functions["pop"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Pop()
	}

	s.Functions["rand"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Push(rand.Float64() < 0.5)
	}

	s.Functions["rot"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Rot()
	}

	s.Functions["shove"] = func(stacks map[string]*Stack) {
		if stacks["boolean"].Len() == 0 || stacks["integer"].Len() == 0 {
			return
		}

		stacks["boolean"].Shove(stacks["boolean"].Pop(), stacks["integer"].Pop().(int64))
	}

	s.Functions["stackdepth"] = func(stacks map[string]*Stack) {
		stacks["integer"].Push(stacks["boolean"].Len())
	}

	s.Functions["swap"] = func(stacks map[string]*Stack) {
		stacks["boolean"].Swap()
	}

	s.Functions["yank"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() == 0 {
			return
		}

		stacks["boolean"].Yank(stacks["integer"].Pop().(int64))
	}

	s.Functions["yankdup"] = func(stacks map[string]*Stack) {
		if stacks["integer"].Len() == 0 {
			return
		}

		stacks["boolean"].YankDup(stacks["integer"].Pop().(int64))
	}

	return s
}

type Options struct {
}

type Interpreter struct {
	Stacks map[string]*Stack
}

var DefaultOptions = Options{}

func NewInterpreter(options Options) *Interpreter {
	interpreter := &Interpreter{
		Stacks: make(map[string]*Stack),
	}

	interpreter.Stacks["integer"] = NewIntStack(options)
	interpreter.Stacks["float"] = NewFloatStack(options)
	interpreter.Stacks["exec"] = new(Stack)
	interpreter.Stacks["boolean"] = NewBooleanStack(options)

	return interpreter
}

func ignoreWhiteSpace(program string) string {
	for i, r := range program {
		if !unicode.IsSpace(r) {
			return program[i:]
		}
	}
	return ""
}

func getToken(program string) (token, remainder string) {
	for i, r := range program {
		if unicode.IsSpace(r) {
			return program[:i], program[i:]
		}
	}
	return program, ""
}

func getToParen(program string) (subprogram, remainder string, err error) {
	parenBalance := 1
	for i, r := range program {
		switch r {
		case '(':
			parenBalance++
		case ')':
			parenBalance--
		}

		if parenBalance == 0 {
			return program[:i], program[i+1:], nil
		}
	}
	return "", "", errors.New("unmatched parentheses")
}

func splitProgram(program string) (result []string, err error) {
	var p, t string

	p = program
	for len(p) > 0 {
		p = ignoreWhiteSpace(p)
		t, p = getToken(p)

		if t == "" {
			continue
		}

		if t == "(" {
			t, p, err = getToParen(p)
			if err != nil {
				return []string{}, err
			}
		}

		result = append(result, t)
	}

	return result, nil
}

func (i *Interpreter) Run(program string) (err error) {
	i.Stacks["exec"].Push(strings.TrimSpace(program))

	for i.Stacks["exec"].Len() > 0 {
		item := i.Stacks["exec"].Pop().(string)

		// If the item on top of the exec stack is a list, push it in
		// reverse order
		if strings.Contains(item, " ") {
			p, err := splitProgram(item)
			if err != nil {
				return err
			}
			for j := len(p) - 1; j >= 0; j-- {
				i.Stacks["exec"].Push(p[j])
			}
			continue
		}

		// Try to parse the item on top of the exec stack as a literal
		if intlit, err := strconv.ParseInt(item, 10, 64); err == nil {
			i.Stacks["integer"].Push(intlit)
			continue
		}

		if floatlit, err := strconv.ParseFloat(item, 64); err == nil {
			i.Stacks["float"].Push(floatlit)
			continue
		}

		if boollit, err := strconv.ParseBool(item); err == nil {
			i.Stacks["boolean"].Push(boollit)
			continue
		}

		// Try to parse the item on top of the exec stack as instruction
		item = strings.ToLower(item)
		if strings.Contains(item, ".") {
			stack := item[:strings.Index(item, ".")]
			operation := item[strings.Index(item, ".")+1:]

			s, ok := i.Stacks[stack]
			if !ok {
				return errors.New(fmt.Sprintf("unkown stack: %v", stack))
			}

			f, ok := s.Functions[operation]
			if !ok {
				return errors.New(fmt.Sprintf("unknown instruction: %v.%v", stack, operation))
			}

			f(i.Stacks)
			continue
		}

		return errors.New(fmt.Sprintf("not an instruction: %q", item))
	}

	return nil
}
<|endoftext|>


<commit_before>// This is the Gordon main application.
// It parses all commandline flags, creates instances of all necessary packages
// and triggers the creation of all worker go-routines.
package main

import (
	"./go/basepath"
	"./go/config"
	"./go/output"
	"./go/stats"
	"./go/taskqueue"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const GordonVersion = "1.1.0"

var (
	configFile  string
	verbose     bool
	logfile     string
	showVersion bool
)

func init() {
	flag.StringVar(&configFile, "c", "", "path to config file")
	flag.StringVar(&logfile, "l", "", "path to logfile")
	flag.BoolVar(&verbose, "v", false, "enable verbose/debugging output")
	flag.BoolVar(&showVersion, "V", false, "show version")
}

func main() {
	flag.Parse()

	if showVersion == true {
		fmt.Printf("Gordon version %s\n", GordonVersion)
		os.Exit(0)
	}

	base, err := basepath.NewBasepath()
	if err != nil {
		log.Fatal("basepath: ", err)
	}

	// When no configuration file was passed as a flag, use the default location.
	if configFile == "" {
		configFile = base.GetPathWith("./gordon.config.json")
	}

	conf, err := config.NewConfig(configFile)
	if err != nil {
		log.Fatal("config: ", err)
	}

	out := output.NewOutput()
	out.SetDebug(verbose)
	out.SetErrorScript(conf.ErrorScript)

	// When no logfile was passed as a flag but it was set in the configuration,
	// use that one instead.
	if logfile == "" && conf.Logfile != "" {
		logfile = base.GetPathWith(conf.Logfile)
	}

	if logfile != "" {
		err = out.SetLogfile(logfile)

		if err != nil {
			log.Fatal("out.SetLogfile(): ", err)
		}
	}

	sta := stats.NewStats()
	sta.SetVersion(GordonVersion)

	tq := taskqueue.NewTaskqueue()
	tq.SetConfig(conf)
	tq.SetOutput(out)
	tq.SetStats(&sta)

	for _, ct := range conf.Tasks {
		ct.Script = base.GetPathWith(ct.Script)
		tq.CreateWorkers(ct)

		sta.InitTask(ct.Type)
	}

	// If the StatsInterface was set, start the HTTP-server for it.
	if conf.StatsInterface != "" {
		if conf.StatsPattern == "" {
			conf.StatsPattern = "/"
		}

		go func() {
			var err error

			if conf.StatsTLSCertFile != "" {
				conf.StatsTLSCertFile = base.GetPathWith(conf.StatsTLSCertFile)
				conf.StatsTLSKeyFile = base.GetPathWith(conf.StatsTLSKeyFile)

				out.Debug("Serving stats on https://" + conf.StatsInterface + conf.StatsPattern)
				err = sta.ServeHttps(conf.StatsInterface, conf.StatsPattern, conf.StatsTLSCertFile, conf.StatsTLSKeyFile)
			} else {
				out.Debug("Serving stats on http://" + conf.StatsInterface + conf.StatsPattern)
				err = sta.ServeHttp(conf.StatsInterface, conf.StatsPattern)
			}

			if err != nil {
				out.NotifyError(fmt.Sprintf("stats.ServeHttp(): %s", err))
			}
		}()
	}

	// Start another go-routine to initiate the graceful shutdown of all taskqueue-workers,
	// when the application shall be terminated.
	cc := make(chan os.Signal)
	signal.Notify(cc, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		<-cc
		tq.Stop()
	}()

	tq.Wait()
}
<commit_msg>version bump<commit_after>// This is the Gordon main application.
// It parses all commandline flags, creates instances of all necessary packages
// and triggers the creation of all worker go-routines.
package main

import (
	"./go/basepath"
	"./go/config"
	"./go/output"
	"./go/stats"
	"./go/taskqueue"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const GordonVersion = "1.2.0"

var (
	configFile  string
	verbose     bool
	logfile     string
	showVersion bool
)

func init() {
	flag.StringVar(&configFile, "c", "", "path to config file")
	flag.StringVar(&logfile, "l", "", "path to logfile")
	flag.BoolVar(&verbose, "v", false, "enable verbose/debugging output")
	flag.BoolVar(&showVersion, "V", false, "show version")
}

func main() {
	flag.Parse()

	if showVersion == true {
		fmt.Printf("Gordon version %s\n", GordonVersion)
		os.Exit(0)
	}

	base, err := basepath.NewBasepath()
	if err != nil {
		log.Fatal("basepath: ", err)
	}

	// When no configuration file was passed as a flag, use the default location.
	if configFile == "" {
		configFile = base.GetPathWith("./gordon.config.json")
	}

	conf, err := config.NewConfig(configFile)
	if err != nil {
		log.Fatal("config: ", err)
	}

	out := output.NewOutput()
	out.SetDebug(verbose)
	out.SetErrorScript(conf.ErrorScript)

	// When no logfile was passed as a flag but it was set in the configuration,
	// use that one instead.
	if logfile == "" && conf.Logfile != "" {
		logfile = base.GetPathWith(conf.Logfile)
	}

	if logfile != "" {
		err = out.SetLogfile(logfile)

		if err != nil {
			log.Fatal("out.SetLogfile(): ", err)
		}
	}

	sta := stats.NewStats()
	sta.SetVersion(GordonVersion)

	tq := taskqueue.NewTaskqueue()
	tq.SetConfig(conf)
	tq.SetOutput(out)
	tq.SetStats(&sta)

	for _, ct := range conf.Tasks {
		ct.Script = base.GetPathWith(ct.Script)
		tq.CreateWorkers(ct)

		sta.InitTask(ct.Type)
	}

	// If the StatsInterface was set, start the HTTP-server for it.
	if conf.StatsInterface != "" {
		if conf.StatsPattern == "" {
			conf.StatsPattern = "/"
		}

		go func() {
			var err error

			if conf.StatsTLSCertFile != "" {
				conf.StatsTLSCertFile = base.GetPathWith(conf.StatsTLSCertFile)
				conf.StatsTLSKeyFile = base.GetPathWith(conf.StatsTLSKeyFile)

				out.Debug("Serving stats on https://" + conf.StatsInterface + conf.StatsPattern)
				err = sta.ServeHttps(conf.StatsInterface, conf.StatsPattern, conf.StatsTLSCertFile, conf.StatsTLSKeyFile)
			} else {
				out.Debug("Serving stats on http://" + conf.StatsInterface + conf.StatsPattern)
				err = sta.ServeHttp(conf.StatsInterface, conf.StatsPattern)
			}

			if err != nil {
				out.NotifyError(fmt.Sprintf("stats.ServeHttp(): %s", err))
			}
		}()
	}

	// Start another go-routine to initiate the graceful shutdown of all taskqueue-workers,
	// when the application shall be terminated.
	cc := make(chan os.Signal)
	signal.Notify(cc, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		<-cc
		tq.Stop()
	}()

	tq.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"strings"
	"log"
	"net"
	"time"
	"strconv"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	const (
	graphite_ip = "192.168.1.138:2003"
	)
	//turn into slice
	x := strings.Split(r.URL.Path, "/")
	//last portion of the slice
	l := x[len(x)-1]
    	//beginning of the slice
	f := x[:len(x)-1]
	//let's turn f into a string
	z := strings.Join(f[:],".")
	//Minor cleanup, want to get rid of that first .
	u := strings.Replace(z, ".", "", 1)
	//let's get the date
	now :=time.Now()
	date := strconv.Itoa(int(now.Unix()))
	// let's concat this into the one thing we want it to be.(newline is necessary)
	packet := u +" "+ l+ " "+date+"\n"
	fmt.Println("processed:", packet)
	fmt.Fprintf(w, r.URL.Path)
	//let's send this stuff to TCP
	fmt.Println("sent:", packet)
	conn, err := net.Dial("tcp", graphite_ip)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	_, err = fmt.Fprintf(conn, packet)
	if err != nil {
		fmt.Printf("fatal error", err)
		return
	}
	if tcpcon, ok := conn.(*net.TCPConn); ok {
		tcpcon.CloseWrite()
	}
	err = conn.Close()
	if err != nil {
		fmt.Printf("fatal error2", err)
	}

}

func main() {
	const (listen_port=":9090" )
	http.HandleFunc("/", sayhelloName) // set router
	err := http.ListenAndServe(listen_port, nil) // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>chaning a thing to a goroutine<commit_after>package main

import (
	"fmt"
	"net/http"
	"strings"
	"log"
	"net"
	"time"
	"strconv"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	const (
	graphite_ip = "192.168.1.138:2003"
	)
	//turn into slice
	x := strings.Split(r.URL.Path, "/")
	//last portion of the slice
	l := x[len(x)-1]
    	//beginning of the slice
	f := x[:len(x)-1]
	//let's turn f into a string
	z := strings.Join(f[:],".")
	//Minor cleanup, want to get rid of that first .
	u := strings.Replace(z, ".", "", 1)
	//let's get the date
	now :=time.Now()
	date := strconv.Itoa(int(now.Unix()))
	// let's concat this into the one thing we want it to be.(newline is necessary)
	packet := u +" "+ l+ " "+date+"\n"
	fmt.Println("processed:", packet)
	fmt.Fprintf(w, r.URL.Path)
	//let's send this stuff to TCP
	fmt.Println("sent:", packet)
	conn, err := net.Dial("tcp", graphite_ip)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	_, err = fmt.Fprintf(conn, packet)
	if err != nil {
		fmt.Printf("fatal error", err)
		return
	}
	if tcpcon, ok := conn.(*net.TCPConn); ok {
		tcpcon.CloseWrite()
	}
	err = conn.Close()
	if err != nil {
		fmt.Printf("fatal error2", err)
	}

}

func main() {
	const (listen_port=":9090" )
	go http.HandleFunc("/", sayhelloName) // set router
	err := http.ListenAndServe(listen_port, nil) // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>