<commit_before>package command

import (
	"fmt"
	"log"
	"time"

	"github.com/igungor/tlbot"
	"golang.org/x/net/context"
)

func init() {
	// XXX: enable them when the time comes.
	// populate()
	// register(cmdPrayerCall)
	// register(cmdFoodFast)
	// register(cmdFoodDawn)
}

var (
	cmdPrayerCall = &Command{
		Name:      "okundumu",
		ShortLine: "is it read?",
		Run:       runPrayerCall,
	}
	cmdFoodFast = &Command{
		Name:      "iftar",
		ShortLine: "seninle iftar ediyorum",
		Run:       runFoodFast,
	}
	cmdFoodDawn = &Command{
		Name:      "sahur",
		ShortLine: "sahura kalkti mi?",
		Run:       runFoodDawn,
	}
)

const (
	timeFormat     = "2 Jan 2006"
	timeFormatLong = "2 Jan 2006 15:04"
	timezone       = "Europe/Istanbul"
)

var noes = []string{
	"hayır",
	"hayır.",
	"Hayır",
	"Hayır.",
	"no",
	"no.",
	"NO.",
	"NO!",
	"NO",
	"nope",
	"nicht",
	"okunmadı",
	"hayır okunmadı",
}

type timePair struct {
	iftar time.Time
	sahur time.Time
}

var callTime = map[string]timePair{}

var _callTime = map[string]struct {
	iftar, sahur string
}{
	"18 Jun 2015": {"20:48", "03:22"},
	"19 Jun 2015": {"20:48", "03:22"},
	"20 Jun 2015": {"20:48", "03:22"},
	"21 Jun 2015": {"20:48", "03:22"},
	"22 Jun 2015": {"20:49", "03:23"},
	"23 Jun 2015": {"20:49", "03:23"},
	"24 Jun 2015": {"20:49", "03:23"},
	"25 Jun 2015": {"20:49", "03:23"},
	"26 Jun 2015": {"20:49", "03:24"},
	"27 Jun 2015": {"20:49", "03:24"},
	"28 Jun 2015": {"20:49", "03:25"},
	"29 Jun 2015": {"20:49", "03:26"},
	"30 Jun 2015": {"20:49", "03:26"},
	"1 Jul 2015":  {"20:49", "03:27"},
	"2 Jul 2015":  {"20:49", "03:28"},
	"3 Jul 2015":  {"20:49", "03:28"},
	"4 Jul 2015":  {"20:49", "03:29"},
	"5 Jul 2015":  {"20:48", "03:30"},
	"6 Jul 2015":  {"20:48", "03:31"},
	"7 Jul 2015":  {"20:48", "03:32"},
	"8 Jul 2015":  {"20:48", "03:33"},
	"9 Jul 2015":  {"20:47", "03:35"},
	"10 Jul 2015": {"20:47", "03:35"},
	"11 Jul 2015": {"20:46", "03:37"},
	"12 Jul 2015": {"20:46", "03:38"},
	"13 Jul 2015": {"20:46", "03:39"},
	"14 Jul 2015": {"20:45", "03:40"},
	"15 Jul 2015": {"20:44", "03:41"},
	"16 Jul 2015": {"20:44", "03:43"},

	"6 Jun 2016":  {"20:41", "03:26"},
	"7 Jun 2016":  {"20:42", "03:26"},
	"8 Jun 2016":  {"20:43", "03:25"},
	"9 Jun 2016":  {"20:43", "03:25"},
	"10 Jun 2016": {"20:44", "03:24"},
	"11 Jun 2016": {"20:44", "03:24"},
	"12 Jun 2016": {"20:45", "03:23"},
	"13 Jun 2016": {"20:45", "03:23"},
	"14 Jun 2016": {"20:46", "03:23"},
	"15 Jun 2016": {"20:46", "03:23"},
	"16 Jun 2016": {"20:46", "03:23"},
	"17 Jun 2016": {"20:47", "03:23"},
	"18 Jun 2016": {"20:47", "03:23"},
	"19 Jun 2016": {"20:47", "03:23"},
	"20 Jun 2016": {"20:48", "03:23"},
	"21 Jun 2016": {"20:48", "03:23"},
	"22 Jun 2016": {"20:48", "03:23"},
	"23 Jun 2016": {"20:48", "03:24"},
	"24 Jun 2016": {"20:48", "03:24"},
	"25 Jun 2016": {"20:49", "03:24"},
	"26 Jun 2016": {"20:49", "03:25"},
	"27 Jun 2016": {"20:49", "03:25"},
	"28 Jun 2016": {"20:49", "03:26"},
	"29 Jun 2016": {"20:49", "03:27"},
	"30 Jun 2016": {"20:49", "03:27"},
	"1 Jul 2016":  {"20:48", "03:28"},
	"2 Jul 2016":  {"20:48", "03:29"},
	"3 Jul 2016":  {"20:48", "03:30"},
	"4 Jul 2016":  {"20:48", "03:31"},
}

func populate() {
	loc, _ := time.LoadLocation(timezone)

	for k, v := range _callTime {
		iftar, _ := time.ParseInLocation(timeFormatLong, fmt.Sprintf("%v %v", k, v.iftar), loc)
		sahur, _ := time.ParseInLocation(timeFormatLong, fmt.Sprintf("%v %v", k, v.sahur), loc)

		callTime[k] = timePair{iftar, sahur}
	}
}

func runPrayerCall(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	switch {
	case !ok:
		txt = "galiba oruç bitti"
	case now.After(timepair.iftar):
		txt = "okundu"
	case now.After(timepair.sahur) && now.Hour() < 6:
		txt = "sahur okundu ama iftara daha çok var"
	case now.Before(timepair.sahur):
		txt = "sahur henüz okunmadı"
	default:
		// after sahur and before iftar, hence NO
		txt = randChoice(noes)
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}

func runFoodFast(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	if ok {
		txt = timepair.iftar.Format("15:04")
	} else {
		txt = "galiba oruç bitti"
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}

func runFoodDawn(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	if ok {
		txt = timepair.sahur.Format("15:04")
	} else {
		txt = "galiba oruç bitti"
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}
<commit_msg>ramadan: enable ramadan<commit_after>package command

import (
	"fmt"
	"log"
	"time"

	"github.com/igungor/tlbot"
	"golang.org/x/net/context"
)

func init() {
	populate()
	register(cmdPrayerCall)
	register(cmdFoodFast)
	register(cmdFoodDawn)
}

var (
	cmdPrayerCall = &Command{
		Name:      "okundumu",
		ShortLine: "is it read?",
		Run:       runPrayerCall,
	}
	cmdFoodFast = &Command{
		Name:      "iftar",
		ShortLine: "seninle iftar ediyorum",
		Run:       runFoodFast,
	}
	cmdFoodDawn = &Command{
		Name:      "sahur",
		ShortLine: "sahura kalkti mi?",
		Run:       runFoodDawn,
	}
)

const (
	timeFormat     = "2 Jan 2006"
	timeFormatLong = "2 Jan 2006 15:04"
	timezone       = "Europe/Istanbul"
)

var noes = []string{
	"hayır",
	"hayır.",
	"Hayır",
	"Hayır.",
	"no",
	"no.",
	"NO.",
	"NO!",
	"NO",
	"nope",
	"nicht",
	"okunmadı",
	"hayır okunmadı",
}

type timePair struct {
	iftar time.Time
	sahur time.Time
}

var callTime = map[string]timePair{}

var _callTime = map[string]struct {
	iftar, sahur string
}{
	"18 Jun 2015": {"20:48", "03:22"},
	"19 Jun 2015": {"20:48", "03:22"},
	"20 Jun 2015": {"20:48", "03:22"},
	"21 Jun 2015": {"20:48", "03:22"},
	"22 Jun 2015": {"20:49", "03:23"},
	"23 Jun 2015": {"20:49", "03:23"},
	"24 Jun 2015": {"20:49", "03:23"},
	"25 Jun 2015": {"20:49", "03:23"},
	"26 Jun 2015": {"20:49", "03:24"},
	"27 Jun 2015": {"20:49", "03:24"},
	"28 Jun 2015": {"20:49", "03:25"},
	"29 Jun 2015": {"20:49", "03:26"},
	"30 Jun 2015": {"20:49", "03:26"},
	"1 Jul 2015":  {"20:49", "03:27"},
	"2 Jul 2015":  {"20:49", "03:28"},
	"3 Jul 2015":  {"20:49", "03:28"},
	"4 Jul 2015":  {"20:49", "03:29"},
	"5 Jul 2015":  {"20:48", "03:30"},
	"6 Jul 2015":  {"20:48", "03:31"},
	"7 Jul 2015":  {"20:48", "03:32"},
	"8 Jul 2015":  {"20:48", "03:33"},
	"9 Jul 2015":  {"20:47", "03:35"},
	"10 Jul 2015": {"20:47", "03:35"},
	"11 Jul 2015": {"20:46", "03:37"},
	"12 Jul 2015": {"20:46", "03:38"},
	"13 Jul 2015": {"20:46", "03:39"},
	"14 Jul 2015": {"20:45", "03:40"},
	"15 Jul 2015": {"20:44", "03:41"},
	"16 Jul 2015": {"20:44", "03:43"},

	"6 Jun 2016":  {"20:41", "03:26"},
	"7 Jun 2016":  {"20:42", "03:26"},
	"8 Jun 2016":  {"20:43", "03:25"},
	"9 Jun 2016":  {"20:43", "03:25"},
	"10 Jun 2016": {"20:44", "03:24"},
	"11 Jun 2016": {"20:44", "03:24"},
	"12 Jun 2016": {"20:45", "03:23"},
	"13 Jun 2016": {"20:45", "03:23"},
	"14 Jun 2016": {"20:46", "03:23"},
	"15 Jun 2016": {"20:46", "03:23"},
	"16 Jun 2016": {"20:46", "03:23"},
	"17 Jun 2016": {"20:47", "03:23"},
	"18 Jun 2016": {"20:47", "03:23"},
	"19 Jun 2016": {"20:47", "03:23"},
	"20 Jun 2016": {"20:48", "03:23"},
	"21 Jun 2016": {"20:48", "03:23"},
	"22 Jun 2016": {"20:48", "03:23"},
	"23 Jun 2016": {"20:48", "03:24"},
	"24 Jun 2016": {"20:48", "03:24"},
	"25 Jun 2016": {"20:49", "03:24"},
	"26 Jun 2016": {"20:49", "03:25"},
	"27 Jun 2016": {"20:49", "03:25"},
	"28 Jun 2016": {"20:49", "03:26"},
	"29 Jun 2016": {"20:49", "03:27"},
	"30 Jun 2016": {"20:49", "03:27"},
	"1 Jul 2016":  {"20:48", "03:28"},
	"2 Jul 2016":  {"20:48", "03:29"},
	"3 Jul 2016":  {"20:48", "03:30"},
	"4 Jul 2016":  {"20:48", "03:31"},
}

func populate() {
	loc, _ := time.LoadLocation(timezone)

	for k, v := range _callTime {
		iftar, _ := time.ParseInLocation(timeFormatLong, fmt.Sprintf("%v %v", k, v.iftar), loc)
		sahur, _ := time.ParseInLocation(timeFormatLong, fmt.Sprintf("%v %v", k, v.sahur), loc)

		callTime[k] = timePair{iftar, sahur}
	}
}

func runPrayerCall(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	switch {
	case !ok:
		txt = "galiba oruç bitti"
	case now.After(timepair.iftar):
		txt = "okundu"
	case now.After(timepair.sahur) && now.Hour() < 6:
		txt = "sahur okundu ama iftara daha çok var"
	case now.Before(timepair.sahur):
		txt = "sahur henüz okunmadı"
	default:
		// after sahur and before iftar, hence NO
		txt = randChoice(noes)
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}

func runFoodFast(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	if ok {
		txt = timepair.iftar.Format("15:04")
	} else {
		txt = "galiba oruç bitti"
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}

func runFoodDawn(ctx context.Context, b *tlbot.Bot, msg *tlbot.Message) {
	loc, _ := time.LoadLocation(timezone)

	now := time.Now().In(loc)
	nowstr := now.Format(timeFormat)

	timepair, ok := callTime[nowstr]
	var txt string
	if ok {
		txt = timepair.sahur.Format("15:04")
	} else {
		txt = "galiba oruç bitti"
	}

	err := b.SendMessage(msg.Chat.ID, txt, tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("Error while sending message. Err: %v\n", err)
		return
	}
}
<|endoftext|>


<commit_before>package libp2pquic

import (
	mrand "math/rand"
	"testing"
	"time"

	"github.com/lucas-clemente/quic-go"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func TestLibp2pQuicTransport(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "libp2p QUIC Transport Suite")
}

var _ = BeforeSuite(func() {
	mrand.Seed(GinkgoRandomSeed())
})

var (
	garbageCollectIntervalOrig time.Duration
	maxUnusedDurationOrig      time.Duration
	origQuicConfig             *quic.Config
)

var _ = BeforeEach(func() {
	garbageCollectIntervalOrig = garbageCollectInterval
	maxUnusedDurationOrig = maxUnusedDuration
	garbageCollectInterval = 50 * time.Millisecond
	maxUnusedDuration = 0
	origQuicConfig = quicConfig
	quicConfig = quicConfig.Clone()
})

var _ = AfterEach(func() {
	garbageCollectInterval = garbageCollectIntervalOrig
	maxUnusedDuration = maxUnusedDurationOrig
	quicConfig = origQuicConfig
})
<commit_msg>remove Ginkgo suite<commit_after><|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"context"
	"os"
	"io/ioutil"
	"os/user"
	"path"

	"github.com/urfave/cli"
	"github.com/cbegin/graven/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
	"github.com/bgentry/speakeasy"
	"github.com/cbegin/graven/util"
	"strings"
)

type ConfigMap map[string]map[string]string
type Validator func(stdout, stderr string) error

var DeployCommand = cli.Command{
	Name: "deploy",
	Usage:       "Deploys artifacts to a repository",
	Action: deploy,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "login",
			Usage: "Prompts for repo login credentials.",
		},
	},
}

func deploy(c *cli.Context) error {
	project, err := domain.FindProject()
	if err != nil {
		return err
	}

	if err := verifyRepoState(project); err != nil {
		return err
	}

	if c.Bool("login") {
		return loginToGithub()
	}

	if err := pkg(c); err != nil {
		return err
	}

	return deployToGithub(project)
}

func loginToGithub() error {
	token, err := readSecret("Please type or paste a github token (will not echo): ")
	config, err := readConfig()
	if err != nil {
		config = ConfigMap{}
	}
	config["github"] = map[string]string{}
	config["github"]["token"] = token
	err = writeConfig(config)
	if err != nil {
		return fmt.Errorf("Error writing configuration file. %v", err)
	}
	return nil
}

func deployToGithub(project *domain.Project) error {

	gh, ctx, err := authenticate()
	if err != nil {
		return err
	}

	repo, ok := project.Repositories["github"]
	if !ok {
		return fmt.Errorf("Sorry, could not find gihub repo configuration")
	}

	ownerName := repo["owner"]
	repoName := repo["repo"]

	tagName := fmt.Sprintf("v%s", project.Version)
	releaseName := tagName
	release := &github.RepositoryRelease{
		TagName: &tagName,
		Name: &releaseName,
	}

	release, _, err = gh.Repositories.CreateRelease(ctx, ownerName, repoName, release)
	if err != nil {
		return err
	}
	fmt.Printf("Created release %v/%v:%v\n", ownerName, repoName, *release.Name)

	for _, a := range project.Artifacts {
		filename := a.ArtifactFile(project)
		sourceFile, err := os.Open(project.TargetPath(filename))
		if err != nil {
			return err
		}
		opts := &github.UploadOptions{
			Name: filename,
		}
		_, _, err = gh.Repositories.UploadReleaseAsset(ctx, ownerName, repoName, *release.ID, opts, sourceFile)
		if err != nil {
			return err
		}
		fmt.Printf("Uploaded %v/%v/%v\n", ownerName, repoName, filename)
	}

	return err
}

func authenticate() (*github.Client, context.Context, error) {
	config, err := readConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Error reading configuration (try: deploy --login): %v", err)
	}

	ctx := context.Background()
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config["github"]["token"]},
	)
	tc := oauth2.NewClient(ctx, ts)

	client := github.NewClient(tc)

	return client, ctx, nil
}

func readSecret(prompt string) (string, error) {
	password, err := speakeasy.Ask(prompt)
	if err != nil {
		return "", fmt.Errorf("Error reading secret from terminal: %v", err)
	}
	return password, nil
}

func readConfig() (ConfigMap, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, err
	}
	file, err := os.Open(path.Join(usr.HomeDir, ".graven.yaml"))
	if err != nil {
		return nil, err
	}
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	config := ConfigMap{}
	err = yaml.Unmarshal(bytes, config)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func writeConfig(config ConfigMap) (error) {
	usr, err := user.Current()
	if err != nil {
		return err
	}
	bytes, err := yaml.Marshal(config)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path.Join(usr.HomeDir, ".graven.yaml"), bytes, 0600)
	if err != nil {
		return err
	}

	return nil
}

func verifyRepoState(project *domain.Project) error {
	remoteName := "origin"
	branchName := "master"

	// Check if on expected branch (e.g. master)
	if err := verifyGitState(func(stdout, stderr string) error {
		actualBranch := strings.TrimSpace(stdout)
		if actualBranch != branchName {
			return fmt.Errorf("Expected to be on branch %v but found branch %v", branchName, actualBranch)
		}
		return nil
	}, project, "rev-parse", "--abbrev-ref", "HEAD"); err != nil {
		return err
	}

	// Ensure no uncommitted changes
	if err := verifyGitState(func(stdout, stderr string) error {
		if strings.TrimSpace(stdout) != "" || strings.TrimSpace(stderr) != "" {
			return fmt.Errorf("Cannot deploy with uncommitted changes.")
		}
		return nil
	}, project, "status", "--porcelain"); err != nil {
		return err
	}

	// Check if changes exist on server
	if err := verifyGitState(func(stdout, stderr string) error {
		fmt.Println(len(strings.Split(strings.TrimSpace(stderr), "\n")))
		return nil
	}, project, "fetch", "--dry-run", remoteName, branchName); err != nil {
		return err
	}

	if err := verifyGitState(func(stdout, stderr string) error {
		return nil
	}, project, "rev-parse", branchName, fmt.Sprintf("%v/%v", remoteName, branchName)); err != nil {
		return err
	}

	return fmt.Errorf("Testing...")
}

func verifyGitState(validator Validator, project *domain.Project, args... string) error {
	sout, serr, err := util.RunCommand(project.ProjectPath(), nil, "git", args...)
	if err != nil {
		return fmt.Errorf("ERROR running Git command: %v\n", err)
	}
	return validator(sout, serr)
}<commit_msg>intermediate commit while working on git validation<commit_after>package commands

import (
	"fmt"
	"context"
	"os"
	"io/ioutil"
	"os/user"
	"path"

	"github.com/urfave/cli"
	"github.com/cbegin/graven/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
	"github.com/bgentry/speakeasy"
	"github.com/cbegin/graven/util"
	"strings"
)

type ConfigMap map[string]map[string]string
type Validator func(stdout, stderr string) error

var DeployCommand = cli.Command{
	Name: "deploy",
	Usage:       "Deploys artifacts to a repository",
	Action: deploy,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "login",
			Usage: "Prompts for repo login credentials.",
		},
	},
}

func deploy(c *cli.Context) error {
	project, err := domain.FindProject()
	if err != nil {
		return err
	}

	if err := verifyRepoState(project); err != nil {
		return err
	}

	if c.Bool("login") {
		return loginToGithub()
	}

	if err := pkg(c); err != nil {
		return err
	}

	return deployToGithub(project)
}

func loginToGithub() error {
	token, err := readSecret("Please type or paste a github token (will not echo): ")
	config, err := readConfig()
	if err != nil {
		config = ConfigMap{}
	}
	config["github"] = map[string]string{}
	config["github"]["token"] = token
	err = writeConfig(config)
	if err != nil {
		return fmt.Errorf("Error writing configuration file. %v", err)
	}
	return nil
}

func deployToGithub(project *domain.Project) error {

	gh, ctx, err := authenticate()
	if err != nil {
		return err
	}

	repo, ok := project.Repositories["github"]
	if !ok {
		return fmt.Errorf("Sorry, could not find gihub repo configuration")
	}

	ownerName := repo["owner"]
	repoName := repo["repo"]

	tagName := fmt.Sprintf("v%s", project.Version)
	releaseName := tagName
	release := &github.RepositoryRelease{
		TagName: &tagName,
		Name: &releaseName,
	}

	release, _, err = gh.Repositories.CreateRelease(ctx, ownerName, repoName, release)
	if err != nil {
		return err
	}
	fmt.Printf("Created release %v/%v:%v\n", ownerName, repoName, *release.Name)

	for _, a := range project.Artifacts {
		filename := a.ArtifactFile(project)
		sourceFile, err := os.Open(project.TargetPath(filename))
		if err != nil {
			return err
		}
		opts := &github.UploadOptions{
			Name: filename,
		}
		_, _, err = gh.Repositories.UploadReleaseAsset(ctx, ownerName, repoName, *release.ID, opts, sourceFile)
		if err != nil {
			return err
		}
		fmt.Printf("Uploaded %v/%v/%v\n", ownerName, repoName, filename)
	}

	return err
}

func authenticate() (*github.Client, context.Context, error) {
	config, err := readConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Error reading configuration (try: deploy --login): %v", err)
	}

	ctx := context.Background()
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config["github"]["token"]},
	)
	tc := oauth2.NewClient(ctx, ts)

	client := github.NewClient(tc)

	return client, ctx, nil
}

func readSecret(prompt string) (string, error) {
	password, err := speakeasy.Ask(prompt)
	if err != nil {
		return "", fmt.Errorf("Error reading secret from terminal: %v", err)
	}
	return password, nil
}

func readConfig() (ConfigMap, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, err
	}
	file, err := os.Open(path.Join(usr.HomeDir, ".graven.yaml"))
	if err != nil {
		return nil, err
	}
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	config := ConfigMap{}
	err = yaml.Unmarshal(bytes, config)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func writeConfig(config ConfigMap) (error) {
	usr, err := user.Current()
	if err != nil {
		return err
	}
	bytes, err := yaml.Marshal(config)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path.Join(usr.HomeDir, ".graven.yaml"), bytes, 0600)
	if err != nil {
		return err
	}

	return nil
}

func verifyRepoState(project *domain.Project) error {
	remoteName := "origin"
	branchName := "master"

	// Check if on expected branch (e.g. master)
	if err := verifyGitState(func(stdout, stderr string) error {
		actualBranch := strings.TrimSpace(stdout)
		if actualBranch != branchName {
			return fmt.Errorf("Expected to be on branch %v but found branch %v", branchName, actualBranch)
		}
		return nil
	}, project, "rev-parse", "--abbrev-ref", "HEAD"); err != nil {
		return err
	}

	// Ensure no uncommitted changes
	if err := verifyGitState(func(stdout, stderr string) error {
		if strings.TrimSpace(stdout) != "" || strings.TrimSpace(stderr) != "" {
			return fmt.Errorf("Cannot deploy with uncommitted changes.")
		}
		return nil
	}, project, "status", "--porcelain"); err != nil {
		return err
	}

	// Check if changes exist on server
	if err := verifyGitState(func(stdout, stderr string) error {
		lineCount := len(strings.Split(strings.TrimSpace(stderr), "\n"))
		fmt.Println(lineCount)
		return nil
	}, project, "fetch", "--dry-run", remoteName, branchName); err != nil {
		return err
	}

	if err := verifyGitState(func(stdout, stderr string) error {
		return nil
	}, project, "rev-parse", branchName, fmt.Sprintf("%v/%v", remoteName, branchName)); err != nil {
		return err
	}

	return fmt.Errorf("Testing...")
}

func verifyGitState(validator Validator, project *domain.Project, args... string) error {
	sout, serr, err := util.RunCommand(project.ProjectPath(), nil, "git", args...)
	if err != nil {
		return fmt.Errorf("ERROR running Git command: %v\n", err)
	}
	return validator(sout, serr)
}<|endoftext|>


<commit_before>package commands

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/provider"
	"github.com/nanobox-io/nanobox/util/data"
)

var (

	// EnvCmd ...
	StatusCmd = &cobra.Command{
		Use:   "status",
		Short: "Manages environment variables in your local dev app.",
		Long:  ``,
		Run:   statusFn,
	}
)

func statusFn(ccmd *cobra.Command, args []string) {
	fmt.Printf("Provider status: %s\n", provider.Status())
	appNames, _ := data.Keys("apps")
	for _, appName := range appNames {
		app := models.App{}
		data.Get("apps", appName, &app)
		fmt.Printf("  %s(%s): %s\n", app.ID, app.Name, app.Status)
	}
}
<commit_msg>updated help summary for the status command<commit_after>package commands

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/provider"
	"github.com/nanobox-io/nanobox/util/data"
)

var (

	// EnvCmd ...
	StatusCmd = &cobra.Command{
		Use:   "status",
		Short: "Displays the status of your Nanobox VM & running platforms.",
		Long:  ``,
		Run:   statusFn,
	}
)

func statusFn(ccmd *cobra.Command, args []string) {
	fmt.Printf("Provider status: %s\n", provider.Status())
	appNames, _ := data.Keys("apps")
	for _, appName := range appNames {
		app := models.App{}
		data.Get("apps", appName, &app)
		fmt.Printf("  %s(%s): %s\n", app.ID, app.Name, app.Status)
	}
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"github.com/gophergala2016/meshbird/network"
	"github.com/miolini/water"
	"log"
	"strconv"
)

type InterfaceService struct {
	BaseService

	localnode *LocalNode
	instance  *water.Interface
	netTable  *NetTable
}

func (is *InterfaceService) Name() string {
	return "iface"
}

func (is *InterfaceService) Init(ln *LocalNode) (err error) {
	is.localnode = ln
	is.netTable = ln.Service("net-table").(*NetTable)
	netsize, _ := ln.State().Secret.Net.Mask.Size()
	IPAddr := fmt.Sprintf("%s/%s", ln.State().PrivateIP, strconv.Itoa(netsize))
	is.instance, err = network.CreateTunInterfaceWithIp("", IPAddr)
	if err != nil {
		return fmt.Errorf("create interface %s err: %s", "", err)
	}
	return nil
}

func (is *InterfaceService) Run() error {
	for {
		buf := make([]byte, 1500)
		n, err := is.instance.Read(buf)
		if err != nil {
			log.Println(err)
			return err
		}
		packet := buf[:n]

		dst := network.IPv4Destination(packet)
		is.netTable.SendPacket(dst, packet)
		log.Printf("[iface] read packet %d bytes", n)
	}
	return nil
}

func (is *InterfaceService) WritePacket(packet []byte) {
	fmt.Printf("[iface] WritePacket received %d bytes", len(packet))
}<commit_msg>Write packet to tun interface<commit_after>package common

import (
	"fmt"
	"github.com/gophergala2016/meshbird/network"
	"github.com/miolini/water"
	"log"
	"strconv"
)

type InterfaceService struct {
	BaseService

	localnode *LocalNode
	instance  *water.Interface
	netTable  *NetTable
}

func (is *InterfaceService) Name() string {
	return "iface"
}

func (is *InterfaceService) Init(ln *LocalNode) (err error) {
	is.localnode = ln
	is.netTable = ln.Service("net-table").(*NetTable)
	netsize, _ := ln.State().Secret.Net.Mask.Size()
	IPAddr := fmt.Sprintf("%s/%s", ln.State().PrivateIP, strconv.Itoa(netsize))
	is.instance, err = network.CreateTunInterfaceWithIp("", IPAddr)
	if err != nil {
		return fmt.Errorf("create interface %s err: %s", "", err)
	}
	return nil
}

func (is *InterfaceService) Run() error {
	for {
		buf := make([]byte, 1500)
		n, err := is.instance.Read(buf)
		if err != nil {
			log.Println(err)
			return err
		}
		packet := buf[:n]

		dst := network.IPv4Destination(packet)
		is.netTable.SendPacket(dst, packet)
		log.Printf("[iface] read packet %d bytes", n)
	}
	return nil
}

func (is *InterfaceService) WritePacket(packet []byte) {
	fmt.Printf("[iface] WritePacket received %d bytes", len(packet))
	is.instance.Write(packet)
}<|endoftext|>


<commit_before>// Copyright (c) 2019 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package compile

import (
	"bufio"
	"bytes"
	"io"
	"math"

	"github.com/tsavola/wag/internal/errorpanic"
	"github.com/tsavola/wag/internal/module"
	"github.com/tsavola/wag/internal/reader"
	"github.com/tsavola/wag/wa"
	"github.com/tsavola/wag/wa/opcode"
)

// rootLib has a dummy function.
var rootLib = module.Library{
	Types: []wa.FuncType{
		wa.FuncType{},
	},
	Funcs: []uint32{
		0,
	},
	CodeFuncs: [][]byte{
		{
			2, // Body size.
			0, // Locals group count.
			byte(opcode.End),
		},
	},
}

type Library struct {
	l module.Library
}

func (mod Module) AsLibrary() (lib Library, err error) {
	defer func() {
		err = errorpanic.Handle(recover())
	}()

	lib = mod.asLibrary()
	return
}

func (mod Module) asLibrary() Library {
	if len(mod.m.Globals) > 0 {
		panic(module.Error("library contains globals"))
	}
	if len(mod.m.ImportGlobals) > 0 {
		panic(module.Error("library imports globals"))
	}
	if len(mod.m.TableFuncs) > 0 {
		panic(module.Error("library uses indirect function calls"))
	}

	libImports := make([]module.ImportIndex, len(mod.m.ImportFuncs))
	for i, imp := range mod.m.ImportFuncs {
		libImports[i] = module.ImportIndex{
			Import:      imp.Import,
			VectorIndex: math.MinInt32, // Outrageous value by default.
		}
	}

	// Copy all arrays in case the originals have excess capacity.
	return Library{module.Library{
		Types:       append([]wa.FuncType{}, mod.m.Types...),
		Funcs:       append([]uint32{}, mod.m.Funcs...),
		ImportFuncs: libImports,
		ExportFuncs: mod.m.ExportFuncs,
	}}
}

func (lib *Library) LoadSections(r Reader) (err error) {
	defer func() {
		err = errorpanic.Handle(recover())
	}()

	lib.loadSections(r)
	return
}

func (lib *Library) loadSections(r Reader) {
	codeBuf := bytes.NewBuffer(nil)

	mapper := &libraryMap{
		reader: reader.Counter{
			R: bufio.NewReader(io.TeeReader(r, codeBuf)),
		},
	}

	r = &mapper.reader

	modImports := make([]module.ImportFunc, len(lib.l.ImportFuncs))
	for i, imp := range lib.l.ImportFuncs {
		modImports[i] = module.ImportFunc{
			Import:      imp.Import,
			LibraryFunc: 0, // In rootLib.
		}
	}

	mod := Module{module.M{
		Types:       lib.l.Types,
		Funcs:       lib.l.Funcs,
		ImportFuncs: modImports,
	}}

	loadCodeSection(&CodeConfig{Mapper: mapper}, r, mod, &rootLib)

	codeBytes := append([]byte{}, codeBuf.Bytes()...) // Avoid excess capacity.
	lib.l.CodeFuncs = make([][]byte, len(mapper.offsets))
	for i, off := range mapper.offsets {
		lib.l.CodeFuncs[i] = codeBytes[off:]
	}

	data := new(DataConfig)
	if err := LoadDataSection(data, r, mod); err != nil {
		panic(err)
	}
	if len(data.GlobalsMemory.Bytes()) > 0 {
		panic(module.Error("library contains data"))
	}
}

// TODO: these methods are copied from Module - combine implementations?

func (l Library) NumImportFuncs() int {
	return len(l.l.ImportFuncs)
}

func (l Library) ImportFunc(i int) (module, field string, sig wa.FuncType) {
	imp := l.l.ImportFuncs[i]
	module = imp.Module
	field = imp.Field

	sigIndex := l.l.Funcs[i]
	sig = l.l.Types[sigIndex]
	return
}

func (l *Library) SetImportFunc(i int, vectorIndex int) {
	if vectorIndex >= 0 {
		panic(vectorIndex)
	}
	l.l.ImportFuncs[i].VectorIndex = vectorIndex
}

func (l Library) ExportFunc(field string) (funcIndex uint32, sig wa.FuncType, found bool) {
	funcIndex, found = l.l.ExportFuncs[field]
	if found {
		sigIndex := l.l.Funcs[funcIndex]
		sig = l.l.Types[sigIndex]
	}
	return
}

func (l *Library) XXX_Internal() interface{} { return &l.l }

type libraryMap struct {
	reader  reader.Counter
	imports int
	offsets []uint32
}

func (m *libraryMap) InitObjectMap(numImportFuncs, numOtherFuncs int) {
	m.imports = numImportFuncs
}

func (m *libraryMap) PutFuncAddr(addr uint32) {
	if m.imports > 0 {
		m.imports--
	} else {
		m.offsets = append(m.offsets, m.reader.N)
	}
}

func (*libraryMap) PutCallSite(uint32, int32)  {}
func (*libraryMap) PutTrapSite(uint32, int32)  {}
func (*libraryMap) PutInsnAddr(uint32)         {}
func (*libraryMap) PutDataBlock(uint32, int32) {}
<commit_msg>compile: no debug mapper stub for library<commit_after>// Copyright (c) 2019 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package compile

import (
	"bufio"
	"bytes"
	"io"
	"math"

	"github.com/tsavola/wag/internal/errorpanic"
	"github.com/tsavola/wag/internal/module"
	"github.com/tsavola/wag/internal/reader"
	"github.com/tsavola/wag/wa"
	"github.com/tsavola/wag/wa/opcode"
)

// rootLib has a dummy function.
var rootLib = module.Library{
	Types: []wa.FuncType{
		wa.FuncType{},
	},
	Funcs: []uint32{
		0,
	},
	CodeFuncs: [][]byte{
		{
			2, // Body size.
			0, // Locals group count.
			byte(opcode.End),
		},
	},
}

type Library struct {
	l module.Library
}

func (mod Module) AsLibrary() (lib Library, err error) {
	defer func() {
		err = errorpanic.Handle(recover())
	}()

	lib = mod.asLibrary()
	return
}

func (mod Module) asLibrary() Library {
	if len(mod.m.Globals) > 0 {
		panic(module.Error("library contains globals"))
	}
	if len(mod.m.ImportGlobals) > 0 {
		panic(module.Error("library imports globals"))
	}
	if len(mod.m.TableFuncs) > 0 {
		panic(module.Error("library uses indirect function calls"))
	}

	libImports := make([]module.ImportIndex, len(mod.m.ImportFuncs))
	for i, imp := range mod.m.ImportFuncs {
		libImports[i] = module.ImportIndex{
			Import:      imp.Import,
			VectorIndex: math.MinInt32, // Outrageous value by default.
		}
	}

	// Copy all arrays in case the originals have excess capacity.
	return Library{module.Library{
		Types:       append([]wa.FuncType{}, mod.m.Types...),
		Funcs:       append([]uint32{}, mod.m.Funcs...),
		ImportFuncs: libImports,
		ExportFuncs: mod.m.ExportFuncs,
	}}
}

func (lib *Library) LoadSections(r Reader) (err error) {
	defer func() {
		err = errorpanic.Handle(recover())
	}()

	lib.loadSections(r)
	return
}

func (lib *Library) loadSections(r Reader) {
	codeBuf := bytes.NewBuffer(nil)

	mapper := &libraryMap{
		reader: reader.Counter{
			R: bufio.NewReader(io.TeeReader(r, codeBuf)),
		},
	}

	r = &mapper.reader

	modImports := make([]module.ImportFunc, len(lib.l.ImportFuncs))
	for i, imp := range lib.l.ImportFuncs {
		modImports[i] = module.ImportFunc{
			Import:      imp.Import,
			LibraryFunc: 0, // In rootLib.
		}
	}

	mod := Module{module.M{
		Types:       lib.l.Types,
		Funcs:       lib.l.Funcs,
		ImportFuncs: modImports,
	}}

	loadCodeSection(&CodeConfig{Mapper: mapper}, r, mod, &rootLib)

	codeBytes := append([]byte{}, codeBuf.Bytes()...) // Avoid excess capacity.
	lib.l.CodeFuncs = make([][]byte, len(mapper.offsets))
	for i, off := range mapper.offsets {
		lib.l.CodeFuncs[i] = codeBytes[off:]
	}

	data := new(DataConfig)
	if err := LoadDataSection(data, r, mod); err != nil {
		panic(err)
	}
	if len(data.GlobalsMemory.Bytes()) > 0 {
		panic(module.Error("library contains data"))
	}
}

// TODO: these methods are copied from Module - combine implementations?

func (l Library) NumImportFuncs() int {
	return len(l.l.ImportFuncs)
}

func (l Library) ImportFunc(i int) (module, field string, sig wa.FuncType) {
	imp := l.l.ImportFuncs[i]
	module = imp.Module
	field = imp.Field

	sigIndex := l.l.Funcs[i]
	sig = l.l.Types[sigIndex]
	return
}

func (l *Library) SetImportFunc(i int, vectorIndex int) {
	if vectorIndex >= 0 {
		panic(vectorIndex)
	}
	l.l.ImportFuncs[i].VectorIndex = vectorIndex
}

func (l Library) ExportFunc(field string) (funcIndex uint32, sig wa.FuncType, found bool) {
	funcIndex, found = l.l.ExportFuncs[field]
	if found {
		sigIndex := l.l.Funcs[funcIndex]
		sig = l.l.Types[sigIndex]
	}
	return
}

func (l *Library) XXX_Internal() interface{} { return &l.l }

type libraryMap struct {
	reader  reader.Counter
	imports int
	offsets []uint32
}

func (m *libraryMap) InitObjectMap(numImportFuncs, numOtherFuncs int) {
	m.imports = numImportFuncs
}

func (m *libraryMap) PutFuncAddr(addr uint32) {
	if m.imports > 0 {
		m.imports--
	} else {
		m.offsets = append(m.offsets, m.reader.N)
	}
}

func (*libraryMap) PutCallSite(uint32, int32)  {}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "log"
    "net/http"
    "io"
    "sync"
    "strings"
    "os/exec"
    "fmt"
    "encoding/xml"
    "io/ioutil"
)

type Config struct {
    Port int
    Slic3rPath string
}

var config = Config{}

func main() {
    //Generate Directories
    if _, err := os.Stat("stl"); os.IsNotExist(err) {
        log.Println("Making Images Directory")
        os.Mkdir("stl", 0777)
    }
    if _, err := os.Stat("gcode"); os.IsNotExist(err) {
        log.Println("Making Scad Directory")
        os.Mkdir("gcode", 0666)
    }
    //Create config file if does not exist
    if _, err := os.Stat("config.xml"); os.IsNotExist(err) {
        log.Println("Making config")
        config.Port = 8080
        config.Slic3rPath = "slic3r"
        xml, err := xml.MarshalIndent(config, "", "    ")
        if (err != nil) {
            panic(err)
            return
        }
        err = ioutil.WriteFile("config.xml", xml, 0666)
        if (err != nil) {
            panic(err)
            return
        }
    } else {
        //Read config file if does exist
        data, err := ioutil.ReadFile("config.xml")
        if (err != nil) {
            panic(err)
            return
        }
        if (string(data) == "") {
            return
        }
        err = xml.Unmarshal(data, &config)
        if (err != nil) {
            panic(err)
            return
        }
    }

    //Start HTTP server
    http.HandleFunc("/", handler)
    http.Handle("/gcode/", http.StripPrefix("/gcode/", http.FileServer(http.Dir("gcode"))))
    log.Printf("HTTP server starting on port :%d\n", config.Port)
    http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil)
}

func handler(writer http.ResponseWriter, request *http.Request) {
    //Reject request if it is not a POST request
    if(request.Method != "POST") {
        http.Error(writer, http.StatusText(400), 400)
        return
    }
    //Get slic3r args
    request.ParseMultipartForm(32 << 20)
    var otherArgs string
	for key, value := range request.Form {
		if(len(value) > 0) {
			otherArgs += fmt.Sprintf(" --%s %s", key, value[0])
		} else {
			otherArgs += fmt.Sprintf(" --%s", key)
		}
	}
    //Get STL file
    tmpFile, header, err := request.FormFile("file")
    if err != nil {
        log.Println(err)
        http.Error(writer, http.StatusText(400), 400)
        return
    }
    defer tmpFile.Close()
    log.Println(header.Header)
    fileName := header.Filename[:(len(header.Filename) - 4)]
    file, err := os.OpenFile("stl/" + header.Filename, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        log.Println(err)
        http.Error(writer, http.StatusText(500), 500)
        return
    }
    io.Copy(file, tmpFile)
    file.Close()
    //Run slic3r with STL file and args
    args := fmt.Sprintf(" stl/%s.stl %s --output gcode/%s.gcode", fileName, otherArgs, fileName)
    wg := new(sync.WaitGroup)
    wg.Add(1)
    go exe_cmd(config.Slic3rPath + args, wg)
    wg.Wait()
    //Return location of gcode file
    writer.Write([]byte("/gcode/" + fileName + ".gcode"))
}

func exe_cmd(cmd string, wg *sync.WaitGroup) {
    log.Println("command is: ", cmd, "\n")
    parts := strings.Fields(cmd)
    head := parts[0]
    parts = parts[1:len(parts)]

    out, err := exec.Command(head, parts...).Output()
    if err != nil {
        log.Printf("%s\n", err)
    }
    log.Printf("%s\n", out)
    wg.Done()
}

<commit_msg>Updated folder permissions<commit_after>package main

import (
    "os"
    "log"
    "net/http"
    "io"
    "sync"
    "strings"
    "os/exec"
    "fmt"
    "encoding/xml"
    "io/ioutil"
)

type Config struct {
    Port int
    Slic3rPath string
}

var config = Config{}

func main() {
    //Generate Directories
    if _, err := os.Stat("stl"); os.IsNotExist(err) {
        log.Println("Making STL Directory")
        os.Mkdir("stl", 0777)
    }
    if _, err := os.Stat("gcode"); os.IsNotExist(err) {
        log.Println("Making Gcode Directory")
        os.Mkdir("gcode", 0777)
    }
    //Create config file if does not exist
    if _, err := os.Stat("config.xml"); os.IsNotExist(err) {
        log.Println("Making config")
        config.Port = 8080
        config.Slic3rPath = "slic3r"
        xml, err := xml.MarshalIndent(config, "", "    ")
        if (err != nil) {
            panic(err)
            return
        }
        err = ioutil.WriteFile("config.xml", xml, 0666)
        if (err != nil) {
            panic(err)
            return
        }
    } else {
        //Read config file if does exist
        data, err := ioutil.ReadFile("config.xml")
        if (err != nil) {
            panic(err)
            return
        }
        if (string(data) == "") {
            return
        }
        err = xml.Unmarshal(data, &config)
        if (err != nil) {
            panic(err)
            return
        }
    }

    //Start HTTP server
    http.HandleFunc("/", handler)
    http.Handle("/gcode/", http.StripPrefix("/gcode/", http.FileServer(http.Dir("gcode"))))
    log.Printf("HTTP server starting on port :%d\n", config.Port)
    http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil)
}

func handler(writer http.ResponseWriter, request *http.Request) {
    //Reject request if it is not a POST request
    if(request.Method != "POST") {
        http.Error(writer, http.StatusText(400), 400)
        return
    }
    //Get slic3r args
    request.ParseMultipartForm(32 << 20)
    var otherArgs string
	for key, value := range request.Form {
		if(len(value) > 0) {
			otherArgs += fmt.Sprintf(" --%s %s", key, value[0])
		} else {
			otherArgs += fmt.Sprintf(" --%s", key)
		}
	}
    //Get STL file
    tmpFile, header, err := request.FormFile("file")
    if err != nil {
        log.Println(err)
        http.Error(writer, http.StatusText(400), 400)
        return
    }
    defer tmpFile.Close()
    log.Println(header.Header)
    fileName := header.Filename[:(len(header.Filename) - 4)]
    file, err := os.OpenFile("stl/" + header.Filename, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        log.Println(err)
        http.Error(writer, http.StatusText(500), 500)
        return
    }
    io.Copy(file, tmpFile)
    file.Close()
    //Run slic3r with STL file and args
    args := fmt.Sprintf(" stl/%s.stl %s --output gcode/%s.gcode", fileName, otherArgs, fileName)
    wg := new(sync.WaitGroup)
    wg.Add(1)
    go exe_cmd(config.Slic3rPath + args, wg)
    wg.Wait()
    //Return location of gcode file
    writer.Write([]byte("/gcode/" + fileName + ".gcode"))
}

func exe_cmd(cmd string, wg *sync.WaitGroup) {
    log.Println("command is: ", cmd, "\n")
    parts := strings.Fields(cmd)
    head := parts[0]
    parts = parts[1:len(parts)]

    out, err := exec.Command(head, parts...).Output()
    if err != nil {
        log.Printf("%s\n", err)
    }
    log.Printf("%s\n", out)
    wg.Done()
}

<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/kless/goconfig/config"
	"log"
	"net/http"
)

var configFile string

type fonduConfig struct {
	DataDir    string
	Port       string
	PypiMirror string
}

var Config = fonduConfig{
	"data",
	"3638",
	"http://pypi.python.org",
}

// Parse flags and set up configuration
func init() {
	flag.StringVar(&configFile, "f", "", "path to a configuration file")
	flag.Parse()

	if configFile != "" {
		c, err := config.ReadDefault(configFile)
		if err != nil {
			log.Println("Unable to load config from: " + configFile)
			return
		}
		d, _ := c.String("fondu", "data_dir")
		if d != "" {
			Config.DataDir = d
		}
		p, _ := c.String("fondu", "port")
		if p != "" {
			Config.Port = p
		}
		m, _ := c.String("fondu", "pypi_mirror")
		if m != "" {
			Config.PypiMirror = m
		}
	}
}

func main() {
	http.HandleFunc("/simple", simpleIndexHandler)
	http.HandleFunc("/simple/", simpleHandler)
	http.Handle("/file/", http.StripPrefix("/file", http.FileServer(http.Dir(Config.DataDir))))
	http.HandleFunc("/fondu/cached-file/", cachedFileHandler)
	http.HandleFunc("/", rootHandler)
	http.HandleFunc("*", http.NotFound)
	log.Println("Starting fondu on port " + Config.Port)
	http.ListenAndServe(":"+Config.Port, nil)
}
<commit_msg>Repository structure was changed<commit_after>package main

import (
	"flag"
	"github.com/kless/goconfig"
	"log"
	"net/http"
)

var configFile string

type fonduConfig struct {
	DataDir    string
	Port       string
	PypiMirror string
}

var Config = fonduConfig{
	"data",
	"3638",
	"http://pypi.python.org",
}

// Parse flags and set up configuration
func init() {
	flag.StringVar(&configFile, "f", "", "path to a configuration file")
	flag.Parse()

	if configFile != "" {
		c, err := config.ReadDefault(configFile)
		if err != nil {
			log.Println("Unable to load config from: " + configFile)
			return
		}
		d, _ := c.String("fondu", "data_dir")
		if d != "" {
			Config.DataDir = d
		}
		p, _ := c.String("fondu", "port")
		if p != "" {
			Config.Port = p
		}
		m, _ := c.String("fondu", "pypi_mirror")
		if m != "" {
			Config.PypiMirror = m
		}
	}
}

func main() {
	http.HandleFunc("/simple", simpleIndexHandler)
	http.HandleFunc("/simple/", simpleHandler)
	http.Handle("/file/", http.StripPrefix("/file", http.FileServer(http.Dir(Config.DataDir))))
	http.HandleFunc("/fondu/cached-file/", cachedFileHandler)
	http.HandleFunc("/", rootHandler)
	http.HandleFunc("*", http.NotFound)
	log.Println("Starting fondu on port " + Config.Port)
	http.ListenAndServe(":"+Config.Port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"fmt"
	"net/http"
	"os/exec"
	"time"

	"./utils/iso8601"

	"github.com/222Labs/common/go/logging"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
)

var (
	AllJobs = make(map[string]*Job)
	log     = logging.GetLogger("kala")
)

type Job struct {
	Name      string     `json:"name"`
	Id        string	 `json:"id"`
	Command   string     `json:"command"`
	Owner     string     `json:"owner"`
	Disabled  bool       `json:"disabled"`
	ChildJobs []*Job     `json:"child_jobs"`

	Schedule     string `json:"schedule"`
	scheduleTime time.Time
	delayDuration *iso8601.Duration

	timesToRepeat int64

	Retries        uint `json:"retries"`
	currentRetries uint

	SuccessCount uint      `json:"success_count"`
	LastSuccess  time.Time `json:"last_success"`
	ErrorCount   uint      `json:"error_count"`
	LastError    time.Time `json:"last_error"`

	LastAttemptedRun time.Time `json:"last_attempted_run"`

	jobTimer *time.Timer

	// TODO
	// Epilson time.Duration `json:""`
	// RunAsUser string `json:""`
	// EnvironmentVariables map[string]string `json:""`
}

func (j *Job) Init() error {
	u4, err := uuid.NewV4()
	if err != nil {
		log.Error("Error occured when generating uuid: %s", err)
		return err
	}
	j.Id = u4.String()

	splitTime := strings.Split(j.Schedule, "/")
	if len(splitTime) != 3 {
		return fmt.Errorf("Schedule not formatted correctly. Should look like: R/2014-03-08T20:00:00Z/PT2H")
	}

	// Handle Repeat Amount
	if splitTime[0] == "R" {
		// Repeat forever
		j.timesToRepeat = -1
	} else {
		j.timesToRepeat, err = strconv.ParseInt(strings.Split(splitTime[0], "R")[1], 10, 0)
		if err != nil {
			log.Error("Error converting timesToRepeat to an int: %s", err)
			return err
		}
	}
	log.Debug("timesToRepeat: %d", j.timesToRepeat)

	j.scheduleTime, err = time.Parse(time.RFC3339, splitTime[1])
	if err != nil {
		log.Error("Error converting scheduleTime to a time.Time: %s", err)
		return err
	}
	if (time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())) < 0 {
		return fmt.Errorf("Schedule time has passed.")
	}
	log.Debug("Schedule Time: %s", j.scheduleTime)

	j.delayDuration, err = iso8601.FromString(splitTime[2])
	if err != nil {
		log.Error("Error converting delayDuration to a time.Duration: %s", err)
		return err
	}
	log.Debug("Delay Duration: %s", j.delayDuration.ToDuration())

	j.StartWaiting()

	return nil
}

func (j *Job) StartWaiting() {
	waitDuration := time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())
	log.Debug("Wait Duration initial: %s", waitDuration)
	if waitDuration < 0 {
		// Needs to be recalculated each time because of Months.
		waitDuration = j.delayDuration.ToDuration()
	}
	log.Info("Job Scheduled to run in: %s", waitDuration)
	j.jobTimer = time.AfterFunc(waitDuration, j.Run)
}

func (j *Job) Disable() {
	//hasBeenStopped := j.jobTimer.Stop()
	_ = j.jobTimer.Stop()
	j.Disabled = true
}

func (j *Job) Run() {
	log.Info("Job %s running", j.Name)

	// Schedule next run
	if j.timesToRepeat != 0 {
		j.timesToRepeat -= 1
		go j.StartWaiting()
	}

	j.LastAttemptedRun = time.Now()

	// TODO - Make thread safe
	// Init retries
	if j.currentRetries == 0 && j.Retries != 0 {
		j.currentRetries = j.Retries
	}

	// Execute command
	args := strings.Split(j.Command, " ")
	cmd := exec.Command(args[0], args[1:]...)
	err := cmd.Run()
	if err != nil {
		log.Error("Run Command got an Error: %s", err)
		j.ErrorCount += 1
		j.LastError = time.Now()
		// Handle retrying
		if j.currentRetries != 0 {
			j.currentRetries -= 0
			j.Run()
		}
		return
	}

	j.SuccessCount += 1
	j.LastSuccess = time.Now()

	// Run Child Jobs
	if len(j.ChildJobs) != 0 {
		for _, job := range j.ChildJobs {
			go job.Run()
		}
	}
}

func main() {
	r := mux.NewRouter()

	apiUrlPrefix := "/api/v1/job/"
	// CRUD
	r.HandleFunc(apiUrlPrefix, handleAddJob).Methods("POST")
	r.HandleFunc(apiUrlPrefix+"{id}", handleJobRequest)
	r.HandleFunc(apiUrlPrefix+"list", handleListJobs).Methods("GET")
	// TODO
	// Manually start a job
	// Adding a dependent job

	log.Info("Starting server...")

	log.Fatal(http.ListenAndServe(":8000", r))
}

type ListJobsResponse struct {
	Jobs map[string]*Job `json:"jobs"`
}

func handleListJobs(w http.ResponseWriter, r *http.Request) {
	resp := &ListJobsResponse{
		Jobs: AllJobs,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}

}

type AddJobResponse struct {
	Id string `json:"id"`
}

func handleAddJob(w http.ResponseWriter, r *http.Request) {
	newJob := &Job{}

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Error("Error occured when reading r.Body: %s", err)
		return
	}
	defer r.Body.Close()

	if err := json.Unmarshal(body, newJob); err != nil {
		// TODO return 400
		//w.Header().Set("Content-Type", "application/json;charset=UTF-8")
		log.Error("Error occured when unmarshalling data: %s", err)
		return
	}

	// TODO
	// 1. Verify there is a scheduled time and a command
	// 2. Verify that "protected" fields were not touched.

	err = newJob.Init()
	if err != nil {
		// TODO return 400
		//w.Header().Set("Content-Type", "application/json;charset=UTF-8")
		log.Error("Error occured when initializing the job: %s", err)
		return
	}
	log.Info("New Job: %#v", newJob)
	AllJobs[newJob.Id] = newJob

	resp := &AddJobResponse{
		Id: newJob.Id,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}
}

func handleJobRequest(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["id"]

	if r.Method == "DELETE" {
		handleDeleteJob(w, r, id)
	} else if r.Method == "GET" {
		handleGetJob(w, r, id)
	}

	// TODO - Method not allow

}

func handleDeleteJob(w http.ResponseWriter, r *http.Request, id string) {
	log.Info("Deleting job: %s", id)
	delete(AllJobs, id)

	w.WriteHeader(http.StatusNoContent)
}

type GetJobResponse struct {
	Job *Job `json:"job"`
}

func handleGetJob(w http.ResponseWriter, r *http.Request, id string) {
	j := AllJobs[id]

	resp := &GetJobResponse{
		Job: j,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}
}
<commit_msg>Added method not allowed protection to route and added return of 400 from create job handler.<commit_after>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"fmt"
	"net/http"
	"os/exec"
	"time"

	"./utils/iso8601"

	"github.com/222Labs/common/go/logging"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
)

var (
	AllJobs = make(map[string]*Job)
	log     = logging.GetLogger("kala")
)

type Job struct {
	Name      string     `json:"name"`
	Id        string	 `json:"id"`
	Command   string     `json:"command"`
	Owner     string     `json:"owner"`
	Disabled  bool       `json:"disabled"`
	ChildJobs []*Job     `json:"child_jobs"`

	Schedule     string `json:"schedule"`
	scheduleTime time.Time
	delayDuration *iso8601.Duration

	timesToRepeat int64

	Retries        uint `json:"retries"`
	currentRetries uint

	SuccessCount uint      `json:"success_count"`
	LastSuccess  time.Time `json:"last_success"`
	ErrorCount   uint      `json:"error_count"`
	LastError    time.Time `json:"last_error"`

	LastAttemptedRun time.Time `json:"last_attempted_run"`

	jobTimer *time.Timer

	// TODO
	// Epilson time.Duration `json:""`
	// RunAsUser string `json:""`
	// EnvironmentVariables map[string]string `json:""`
}

func (j *Job) Init() error {
	u4, err := uuid.NewV4()
	if err != nil {
		log.Error("Error occured when generating uuid: %s", err)
		return err
	}
	j.Id = u4.String()

	splitTime := strings.Split(j.Schedule, "/")
	if len(splitTime) != 3 {
		return fmt.Errorf("Schedule not formatted correctly. Should look like: R/2014-03-08T20:00:00Z/PT2H")
	}

	// Handle Repeat Amount
	if splitTime[0] == "R" {
		// Repeat forever
		j.timesToRepeat = -1
	} else {
		j.timesToRepeat, err = strconv.ParseInt(strings.Split(splitTime[0], "R")[1], 10, 0)
		if err != nil {
			log.Error("Error converting timesToRepeat to an int: %s", err)
			return err
		}
	}
	log.Debug("timesToRepeat: %d", j.timesToRepeat)

	j.scheduleTime, err = time.Parse(time.RFC3339, splitTime[1])
	if err != nil {
		log.Error("Error converting scheduleTime to a time.Time: %s", err)
		return err
	}
	if (time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())) < 0 {
		return fmt.Errorf("Schedule time has passed.")
	}
	log.Debug("Schedule Time: %s", j.scheduleTime)

	j.delayDuration, err = iso8601.FromString(splitTime[2])
	if err != nil {
		log.Error("Error converting delayDuration to a time.Duration: %s", err)
		return err
	}
	log.Debug("Delay Duration: %s", j.delayDuration.ToDuration())

	j.StartWaiting()

	return nil
}

func (j *Job) StartWaiting() {
	waitDuration := time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())
	log.Debug("Wait Duration initial: %s", waitDuration)
	if waitDuration < 0 {
		// Needs to be recalculated each time because of Months.
		waitDuration = j.delayDuration.ToDuration()
	}
	log.Info("Job Scheduled to run in: %s", waitDuration)
	j.jobTimer = time.AfterFunc(waitDuration, j.Run)
}

func (j *Job) Disable() {
	//hasBeenStopped := j.jobTimer.Stop()
	_ = j.jobTimer.Stop()
	j.Disabled = true
}

func (j *Job) Run() {
	log.Info("Job %s running", j.Name)

	// Schedule next run
	if j.timesToRepeat != 0 {
		j.timesToRepeat -= 1
		go j.StartWaiting()
	}

	j.LastAttemptedRun = time.Now()

	// TODO - Make thread safe
	// Init retries
	if j.currentRetries == 0 && j.Retries != 0 {
		j.currentRetries = j.Retries
	}

	// Execute command
	args := strings.Split(j.Command, " ")
	cmd := exec.Command(args[0], args[1:]...)
	err := cmd.Run()
	if err != nil {
		log.Error("Run Command got an Error: %s", err)
		j.ErrorCount += 1
		j.LastError = time.Now()
		// Handle retrying
		if j.currentRetries != 0 {
			j.currentRetries -= 0
			j.Run()
		}
		return
	}

	j.SuccessCount += 1
	j.LastSuccess = time.Now()

	// Run Child Jobs
	if len(j.ChildJobs) != 0 {
		for _, job := range j.ChildJobs {
			go job.Run()
		}
	}
}

func main() {
	r := mux.NewRouter()

	apiUrlPrefix := "/api/v1/job/"
	// CRUD
	r.HandleFunc(apiUrlPrefix, handleAddJob).Methods("POST")
	r.HandleFunc(apiUrlPrefix+"{id}", handleJobRequest).Methods("DELETE", "GET")
	r.HandleFunc(apiUrlPrefix+"list", handleListJobs).Methods("GET")
	// TODO
	// Manually start a job
	// Adding a dependent job

	log.Info("Starting server...")

	log.Fatal(http.ListenAndServe(":8000", r))
}

type ListJobsResponse struct {
	Jobs map[string]*Job `json:"jobs"`
}

func handleListJobs(w http.ResponseWriter, r *http.Request) {
	resp := &ListJobsResponse{
		Jobs: AllJobs,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}

}

type AddJobResponse struct {
	Id string `json:"id"`
}

func handleAddJob(w http.ResponseWriter, r *http.Request) {
	newJob := &Job{}

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Error("Error occured when reading r.Body: %s", err)
		return
	}
	defer r.Body.Close()

	if err := json.Unmarshal(body, newJob); err != nil {
		errStr := "Error occured when unmarshalling data"
		log.Error(errStr + ": %s", err)
		http.Error(w, errStr, 400)
		return
	}

	// TODO
	// 2. Verify that "protected" fields were not touched.

	err = newJob.Init()
	if err != nil {
		errStr := "Error occured when initializing the job"
		log.Error(errStr + ": %s", err)
		http.Error(w, errStr, 400)
		return
	}
	log.Info("New Job: %#v", newJob)
	AllJobs[newJob.Id] = newJob

	resp := &AddJobResponse{
		Id: newJob.Id,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}
}

func handleJobRequest(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["id"]

	if r.Method == "DELETE" {
		handleDeleteJob(w, r, id)
	} else if r.Method == "GET" {
		handleGetJob(w, r, id)
	}
}

func handleDeleteJob(w http.ResponseWriter, r *http.Request, id string) {
	log.Info("Deleting job: %s", id)
	delete(AllJobs, id)

	w.WriteHeader(http.StatusNoContent)
}

type GetJobResponse struct {
	Job *Job `json:"job"`
}

func handleGetJob(w http.ResponseWriter, r *http.Request, id string) {
	j := AllJobs[id]

	resp := &GetJobResponse{
		Job: j,
	}

	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		log.Error("Error occured when marshalling response: %s", err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "errors"
    "bufio"
    "regexp"
    "strings"
    "time"
    "os"
)

type Channel struct{
    UserCount uint
    LineCount uint
    WordCount uint
    MaxDay uint
    Mean int64
    First int64
    Last int64
}

type LogReader struct{
    Channel Channel
    Users map[string]User
    LastGenerated int64
    RegexAction *regexp.Regexp
    RegexMessage *regexp.Regexp
    RegexParseAction *regexp.Regexp
    RegexParseMessage *regexp.Regexp
}

func (lr *LogReader) AddUser(u User) {
    if lr.HasUser(u.Username) == true {
        panic("Adding a user that already exists in database")
    }
    lr.SetUser(u.Username, u)
}

func (lr LogReader) HasUser(nick string) bool {
    if _, ok := lr.Users[nick]; ok {
        return true
    }
    return false
}

func (lr *LogReader) SetUser(nick string, u User) {
    lr.Users[nick] = u
}

func (lr LogReader) GetUser(nick string) (user User, err error) {
    if lr.HasUser(nick) == false {
        err = errors.New("User doesn't exist")
        return
    }
    user = lr.Users[nick]
    return
}

func (lr *LogReader) LoadFile(path string) bool {

    // Open the file
    f, err := os.Open(path)

    if (err != nil) {
        return false
    }

    // Create Buffered Scanner
    scanner := bufio.NewScanner(f)

    // Loop over all found lines and analyse them
    for scanner.Scan() {
        line := scanner.Text()

        if lr.RegexAction.MatchString(line) == true {
            lr.ParseLine(line, true)
        } else if lr.RegexMessage.MatchString(line) == true {
            lr.ParseLine(line, false)
        } else {
            fmt.Printf("error reading line [%i]\n", lr.Channel.LineCount)
        }
    }
    return true;
}

func (lr LogReader) ParseTime(inputDate string) time.Time {
    // Convert timestamp into unix timestamp
    // @todo make input format configurable
    lineTime, err := time.Parse("2006-01-02 15:04:05 -0700", inputDate)
    if err != nil {
        panic(err)
    }
    return lineTime
}

func (lr LogReader) IsUserIgnored(username string) bool {
    return true
}

func (lr *LogReader) ParseLine(line string, isAction bool) bool {

    var parsed[][]string
    var user User

    fmt.Println("Parsing Line: [" + line + "]\n\n")
    // timestamp = [0][1]
    // nick = [0][2]
    // message/action = [0][3]
    if isAction == true {
        parsed = lr.RegexParseAction.FindAllStringSubmatch(line, -1)
    }else{
        parsed = lr.RegexParseMessage.FindAllStringSubmatch(line, -1)
    }

    // Convert timestamp into unix timestamp
    lineTime := lr.ParseTime(parsed[0][1])
    if lineTime.Unix() < lr.LastGenerated {
        return false
    }

    // Parse nick and check against ignore list
    lineNick := strings.Trim(strings.ToLower(parsed[0][2]), " ")
    // @todo check against ignore list

    // Parse message
    lineMessage := strings.Trim(parsed[0][3], " ")

    // If this is an empty line lets ignore it
    if lineMessage == "" {
        return false
    }

    // Get user, if not found make a new user
    if lr.HasUser(lineNick) == true {
        user,_ = lr.GetUser(lineNick)
    }else{
        user = NewUser(lineNick, lineTime.Unix())
    }

    lineMessageCharCount := (strings.Count(lineMessage, "") - 1)
    lineMessageWords := strings.Split(strings.ToLower(lineMessage), " ")
    lineMessageWordCount := len(lineMessageWords)

    user.Words = append(user.Words, lineMessageWords...)

    lr.Channel.LineCount++
    user.LineCount++

    user.WordCount += uint(lineMessageWordCount)
    lr.Channel.WordCount += uint(lineMessageWordCount)
    user.CharCount += uint(lineMessageCharCount)

    // Increment Days
    if _, ok := user.Days[lineTime.Format("2006-02-01")]; ok {
        user.Days[lineTime.Format("2006-01-02")]++
    }else{
        user.Days[lineTime.Format("2006-01-02")] = 1
    }

    // Incremember Hours
    user.Hours[uint(lineTime.Hour())]++

    // Set first and last seen timestamps
    if user.FirstSeen > lineTime.Unix() {
        user.FirstSeen = lineTime.Unix()
    }

    if user.LastSeen < lineTime.Unix() {
        user.LastSeen = lineTime.Unix()
    }

    if lr.Channel.First == 0 {
        lr.Channel.First = lineTime.Unix()
    }

    if lr.Channel.Last == 0 {
        lr.Channel.Last = lineTime.Unix()
    }

    if lr.Channel.First > lineTime.Unix() {
        lr.Channel.First = lineTime.Unix()
    }

    if lr.Channel.Last < lineTime.Unix() {
        lr.Channel.Last = lineTime.Unix()
    }

    lr.SetUser(lineNick, user)
    return true
}

func main() {
    lr := LogReader{
        RegexAction: regexp.MustCompile(`^\[(.+)\] \* (.+)$`),
        RegexMessage: regexp.MustCompile(`^\[(.+)\] <(.+)> (.+)$`),
        RegexParseAction: regexp.MustCompile(`^\[(.+)\] \* (\S+) (.+)$`),
        RegexParseMessage: regexp.MustCompile(`^\[(.+)\] <(\S+)> (.+)$`),
        Users: make(map[string]User),
    }

    lr.LoadFile("irctest.log")

    //u.CalculateTotals()
    fmt.Printf("%v\n", lr)
}
<commit_msg>Setting up database for loading/saving stats<commit_after>package main

import (
    "fmt"
    "errors"
    "bufio"
    "regexp"
    "strings"
    "time"
    "os"
)

type LogReader struct{
    Database Database
    Channel Channel
    Users map[string]User
    LastGenerated int64
    RegexAction *regexp.Regexp
    RegexMessage *regexp.Regexp
    RegexParseAction *regexp.Regexp
    RegexParseMessage *regexp.Regexp
}

func (lr *LogReader) AddUser(u User) {
    if lr.HasUser(u.Username) == true {
        panic("Adding a user that already exists in database")
    }
    lr.SetUser(u.Username, u)
}

func (lr LogReader) HasUser(nick string) bool {
    if _, ok := lr.Users[nick]; ok {
        return true
    }
    return false
}

func (lr *LogReader) SetUser(nick string, u User) {
    lr.Users[nick] = u
}

func (lr LogReader) GetUser(nick string) (user User, err error) {
    if lr.HasUser(nick) == false {
        err = errors.New("User doesn't exist")
        return
    }
    user = lr.Users[nick]
    return
}

func (lr *LogReader) LoadFile(path string) bool {
    // Open the file
    f, err := os.Open(path)

    if (err != nil) {
        return false
    }

    // Create Buffered Scanner
    scanner := bufio.NewScanner(f)

    // Loop over all found lines and analyse them
    for scanner.Scan() {
        line := scanner.Text()
        if lr.RegexAction.MatchString(line) == true {
            lr.ParseLine(line, true)
        } else if lr.RegexMessage.MatchString(line) == true {
            lr.ParseLine(line, false)
        } else {
            fmt.Printf("error reading line [%i]\n", lr.Channel.LineCount)
        }
    }
    return true;
}

func (lr LogReader) ParseTime(inputDate string) time.Time {
    // Convert timestamp into unix timestamp
    // @todo make input format configurable
    lineTime, err := time.Parse("2006-01-02 15:04:05 -0700", inputDate)
    if err != nil {
        panic(err)
    }
    return lineTime
}

func (lr LogReader) IsUserIgnored(username string) bool {
    return true
}

func (lr *LogReader) ParseLine(line string, isAction bool) bool {
    var parsed[][]string
    var user User

    fmt.Println("Parsing Line: [" + line + "]\n\n")
    // timestamp = [0][1]
    // nick = [0][2]
    // message/action = [0][3]
    if isAction == true {
        parsed = lr.RegexParseAction.FindAllStringSubmatch(line, -1)
    }else{
        parsed = lr.RegexParseMessage.FindAllStringSubmatch(line, -1)
    }

    // Convert timestamp into unix timestamp
    lineTime := lr.ParseTime(parsed[0][1])
    if lineTime.Unix() < lr.LastGenerated {
        return false
    }

    // Parse nick and check against ignore list
    lineNick := strings.Trim(strings.ToLower(parsed[0][2]), " ")
    // @todo check against ignore list

    // Parse message
    lineMessage := strings.Trim(parsed[0][3], " ")

    // If this is an empty line lets ignore it
    if lineMessage == "" {
        return false
    }

    // Get user, if not found make a new user
    if lr.HasUser(lineNick) == true {
        user,_ = lr.GetUser(lineNick)
    }else{
        user = NewUser(lineNick, lineTime.Unix())
    }

    lineMessageCharCount := (strings.Count(lineMessage, "") - 1)
    lineMessageWords := strings.Split(strings.ToLower(lineMessage), " ")
    lineMessageWordCount := len(lineMessageWords)

    user.Words = append(user.Words, lineMessageWords...)

    lr.Channel.LineCount++
    user.LineCount++

    user.WordCount += uint(lineMessageWordCount)
    lr.Channel.WordCount += uint(lineMessageWordCount)
    user.CharCount += uint(lineMessageCharCount)

    // Increment Days
    if _, ok := user.Days[lineTime.Format("2006-02-01")]; ok {
        user.Days[lineTime.Format("2006-01-02")]++
    }else{
        user.Days[lineTime.Format("2006-01-02")] = 1
    }

    // Incremember Hours
    user.Hours[uint(lineTime.Hour())]++

    // Set first and last seen timestamps
    if user.FirstSeen > lineTime.Unix() {
        user.FirstSeen = lineTime.Unix()
    }

    if user.LastSeen < lineTime.Unix() {
        user.LastSeen = lineTime.Unix()
    }

    if lr.Channel.First == 0 {
        lr.Channel.First = lineTime.Unix()
    }

    if lr.Channel.Last == 0 {
        lr.Channel.Last = lineTime.Unix()
    }

    if lr.Channel.First > lineTime.Unix() {
        lr.Channel.First = lineTime.Unix()
    }

    if lr.Channel.Last < lineTime.Unix() {
        lr.Channel.Last = lineTime.Unix()
    }

    lr.SetUser(lineNick, user)
    return true
}

func main() {
    db := Database{}
    db.Load("db.bin")

    lr := LogReader{
        RegexAction: regexp.MustCompile(`^\[(.+)\] \* (.+)$`),
        RegexMessage: regexp.MustCompile(`^\[(.+)\] <(.+)> (.+)$`),
        RegexParseAction: regexp.MustCompile(`^\[(.+)\] \* (\S+) (.+)$`),
        RegexParseMessage: regexp.MustCompile(`^\[(.+)\] <(\S+)> (.+)$`),
        Users: make(map[string]User),
	Database: db,
    }

    lr.LoadFile("irctest.log")

    db.Save("db.bin")

    //u.CalculateTotals()
    fmt.Printf("%v\n", lr)
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	"fmt"
	"strings"

	acceptance "github.com/cloudfoundry/bosh-bootloader/acceptance-tests"
	"github.com/cloudfoundry/bosh-bootloader/acceptance-tests/actors"
	"github.com/cloudfoundry/bosh-bootloader/testhelpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("lbs test", func() {
	var (
		bbl     actors.BBL
		aws     actors.AWS
		bosh    actors.BOSH
		boshcli actors.BOSHCLI
		state   acceptance.State

		certPath       string
		chainPath      string
		keyPath        string
		otherCertPath  string
		otherChainPath string
		otherKeyPath   string
		vpcName        string
	)

	BeforeEach(func() {
		var err error
		configuration, err := acceptance.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration, "lbs-env")
		aws = actors.NewAWS(configuration)
		bosh = actors.NewBOSH()
		boshcli = actors.NewBOSHCLI()
		state = acceptance.NewState(configuration.StateFileDir)

		certPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		chainPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_CHAIN)
		Expect(err).NotTo(HaveOccurred())

		keyPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		otherCertPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		otherKeyPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		otherChainPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_CHAIN)
		Expect(err).NotTo(HaveOccurred())

		bbl.Up(actors.AWSIAAS, []string{"--name", bbl.PredefinedEnvID(), "--no-director"})

		vpcName = fmt.Sprintf("%s-vpc", bbl.PredefinedEnvID())
	})

	AfterEach(func() {
		if !CurrentGinkgoTestDescription().Failed {
			bbl.Destroy()
		}
	})

	It("creates, updates and deletes a concourse LB with the specified cert and key", func() {
		By("verifying there are no load balancers", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})

		By("creating a concourse lb", func() {
			bbl.CreateLB("concourse", certPath, keyPath, chainPath)

			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(1))
			Expect(aws.LoadBalancers(vpcName)).To(Equal([]string{fmt.Sprintf("%s-concourse-lb", bbl.PredefinedEnvID())}))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(testhelpers.BBL_CERT)))
		})

		By("verifying that the bbl lbs output contains the concourse lb", func() {
			session := bbl.LBs()
			stdout := string(session.Out.Contents())
			Expect(stdout).To(MatchRegexp("Concourse LB: .*"))
		})

		By("updating the certs of the lb", func() {
			bbl.UpdateLB(otherCertPath, otherKeyPath, otherChainPath)
			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(1))
			Expect(aws.LoadBalancers(vpcName)).To(Equal([]string{fmt.Sprintf("%s-concourse-lb", bbl.PredefinedEnvID())}))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(string(testhelpers.OTHER_BBL_CERT))))
		})

		By("deleting lbs", func() {
			bbl.DeleteLBs()
		})

		By("confirming that the concourse lb does not exist", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})
	})

	It("creates, updates and deletes cf LBs with the specified cert and key", func() {
		By("verifying there are no load balancers", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})

		By("creating cf lbs", func() {
			bbl.CreateLB("cf", certPath, keyPath, chainPath)

			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(3))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(
				MatchRegexp(".*-cf-router-lb"),
				MatchRegexp(".*-cf-ssh-lb"),
				MatchRegexp(".*-cf-tcp-lb"),
			))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(testhelpers.BBL_CERT)))
		})

		By("verifying that the bbl lbs output contains the cf lbs", func() {
			session := bbl.LBs()
			stdout := string(session.Out.Contents())
			Expect(stdout).To(MatchRegexp("CF Router LB: .*"))
			Expect(stdout).To(MatchRegexp("CF SSH Proxy LB: .*"))
			Expect(stdout).To(MatchRegexp("CF TCP Router LB: .*"))
		})

		By("updating the certs of the cf router lb", func() {
			bbl.UpdateLB(otherCertPath, otherKeyPath, otherChainPath)
			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(3))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(
				MatchRegexp(".*-cf-router-lb"),
				MatchRegexp(".*-cf-ssh-lb"),
				MatchRegexp(".*-cf-tcp-lb"),
			))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(string(testhelpers.OTHER_BBL_CERT))))
		})

		By("deleting lbs", func() {
			bbl.DeleteLBs()
		})

		By("confirming that the cf lbs do not exist", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})
	})
})
<commit_msg>AWS LBs test uses regexes to match LB names<commit_after>package acceptance_test

import (
	"fmt"
	"strings"

	acceptance "github.com/cloudfoundry/bosh-bootloader/acceptance-tests"
	"github.com/cloudfoundry/bosh-bootloader/acceptance-tests/actors"
	"github.com/cloudfoundry/bosh-bootloader/testhelpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("lbs test", func() {
	var (
		bbl     actors.BBL
		aws     actors.AWS
		bosh    actors.BOSH
		boshcli actors.BOSHCLI
		state   acceptance.State

		certPath       string
		chainPath      string
		keyPath        string
		otherCertPath  string
		otherChainPath string
		otherKeyPath   string
		vpcName        string
	)

	BeforeEach(func() {
		var err error
		configuration, err := acceptance.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration, "lbs-env")
		aws = actors.NewAWS(configuration)
		bosh = actors.NewBOSH()
		boshcli = actors.NewBOSHCLI()
		state = acceptance.NewState(configuration.StateFileDir)

		certPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		chainPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_CHAIN)
		Expect(err).NotTo(HaveOccurred())

		keyPath, err = testhelpers.WriteContentsToTempFile(testhelpers.BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		otherCertPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		otherKeyPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		otherChainPath, err = testhelpers.WriteContentsToTempFile(testhelpers.OTHER_BBL_CHAIN)
		Expect(err).NotTo(HaveOccurred())

		bbl.Up(actors.AWSIAAS, []string{"--name", bbl.PredefinedEnvID(), "--no-director"})

		vpcName = fmt.Sprintf("%s-vpc", bbl.PredefinedEnvID())
	})

	AfterEach(func() {
		if !CurrentGinkgoTestDescription().Failed {
			bbl.Destroy()
		}
	})

	It("creates, updates and deletes a concourse LB with the specified cert and key", func() {
		By("verifying there are no load balancers", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})

		By("creating a concourse lb", func() {
			bbl.CreateLB("concourse", certPath, keyPath, chainPath)

			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(1))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(MatchRegexp(".*-concourse-lb")))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(testhelpers.BBL_CERT)))
		})

		By("verifying that the bbl lbs output contains the concourse lb", func() {
			session := bbl.LBs()
			stdout := string(session.Out.Contents())
			Expect(stdout).To(MatchRegexp("Concourse LB: .*"))
		})

		By("updating the certs of the lb", func() {
			bbl.UpdateLB(otherCertPath, otherKeyPath, otherChainPath)
			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(1))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(MatchRegexp(".*-concourse-lb")))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(string(testhelpers.OTHER_BBL_CERT))))
		})

		By("deleting lbs", func() {
			bbl.DeleteLBs()
		})

		By("confirming that the concourse lb does not exist", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})
	})

	It("creates, updates and deletes cf LBs with the specified cert and key", func() {
		By("verifying there are no load balancers", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})

		By("creating cf lbs", func() {
			bbl.CreateLB("cf", certPath, keyPath, chainPath)

			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(3))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(
				MatchRegexp(".*-cf-router-lb"),
				MatchRegexp(".*-cf-ssh-lb"),
				MatchRegexp(".*-cf-tcp-lb"),
			))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(testhelpers.BBL_CERT)))
		})

		By("verifying that the bbl lbs output contains the cf lbs", func() {
			session := bbl.LBs()
			stdout := string(session.Out.Contents())
			Expect(stdout).To(MatchRegexp("CF Router LB: .*"))
			Expect(stdout).To(MatchRegexp("CF SSH Proxy LB: .*"))
			Expect(stdout).To(MatchRegexp("CF TCP Router LB: .*"))
		})

		By("updating the certs of the cf router lb", func() {
			bbl.UpdateLB(otherCertPath, otherKeyPath, otherChainPath)
			Expect(aws.LoadBalancers(vpcName)).To(HaveLen(3))
			Expect(aws.LoadBalancers(vpcName)).To(ConsistOf(
				MatchRegexp(".*-cf-router-lb"),
				MatchRegexp(".*-cf-ssh-lb"),
				MatchRegexp(".*-cf-tcp-lb"),
			))

			certificateName := aws.GetSSLCertificateNameFromLBs(bbl.PredefinedEnvID())
			Expect(strings.TrimSpace(aws.DescribeCertificate(certificateName).Body)).To(Equal(strings.TrimSpace(string(testhelpers.OTHER_BBL_CERT))))
		})

		By("deleting lbs", func() {
			bbl.DeleteLBs()
		})

		By("confirming that the cf lbs do not exist", func() {
			Expect(aws.LoadBalancers(vpcName)).To(BeEmpty())
		})
	})
})
<|endoftext|>


<commit_before>//
// nntp.go
//
package main

import (
	"bufio"
	"bytes"
	"io/ioutil"
	"log"
	"net"
	"strings"
)

type ConnectionInfo struct {
	mode string
	newsgroup string
	allowsPosting bool
	supportsStream bool
}

type NNTPConnection struct {
	conn net.Conn
	reader *bufio.Reader
	inbound bool
	debug bool
	info *ConnectionInfo
	policy *FeedPolicy
	send chan *NNTPMessage
}

func (self *NNTPConnection) HandleOutbound(d *NNTPDaemon) {
	line := self.ReadLine()
	self.info.allowsPosting = strings.HasPrefix(line, "200 ")
	// they allow posting
	// send capabilities command
	self.SendLine("CAPABILITIES")

	// get capabilites
	for {
		line = strings.ToLower(self.ReadLine())
		if line == ".\r\n" {
			// done reading capabilities
			break
		}
		if line == "streaming\r\n" {
			self.info.supportsStream = true
		} else if line == "postihavestreaming\r\n" {
			self.info.supportsStream = true
		}
	}

	// if they support streaming and allow posting continue
	// otherwise quit
	if ! self.info.supportsStream || ! self.info.allowsPosting {
		if self.debug {
			log.Println(self.info.supportsStream, self.info.allowsPosting)
		}

		self.Quit()
		return
	}
	self.SendLine("MODE STREAM")
	line = self.ReadLine()
	if strings.HasPrefix(line, "203 ") {
		self.info.mode = "stream"
		log.Println("streaming mode activated")
	} else {
		self.Quit()
		return
	}
	// mainloop
	for  {
		// poll for new message
		message := <- self.send
		// check if we allow it
		if ! self.policy.AllowsNewsgroup(message.Newsgroup) {
			log.Println("not federating article", message.MessageID, "beause it's in", message.Newsgroup)
			continue
		}
		log.Println("send article")
		// send check
		self.Send("CHECK ")
		self.SendLine(message.MessageID)
		line = self.ReadLine()
		if strings.HasPrefix(line, "238 ") {
			// accepted
			// send it
			self.Send("TAKETHIS ")
			self.SendLine(message.MessageID)
			// load file
			data, err := ioutil.ReadFile(d.store.GetFilename(message.MessageID))
			if err != nil {
				log.Fatal("failed to read article", message.MessageID)
			}
			// split into lines
			parts := bytes.Split(data,[]byte{'\n'})
			// for each line send it
			for idx := range parts {
				ba := parts[idx]
				self.SendBytes(ba)
				self.Send("\r\n")
			}
			// send delimiter
			self.SendLine(".")
			// check for success / fail
			line := self.ReadLine()
			if strings.HasPrefix(line, "239 ") {
				log.Println("Article", message.MessageID, "sent")
			} else {
				log.Println("Article", message.MessageID, "failed to send", line)
			}
			// continue
			continue
		} else if strings.HasPrefix(line, "435 ") {
			// already have it
			if self.debug {
				log.Println(message.MessageID, "already owned")
			}
		} else if strings.HasPrefix(line, "437 ") {
			// article banned
			log.Println(message.MessageID, "was banned")
		}
	}
}

// handle inbound connection
func (self *NNTPConnection) HandleInbound(d *NNTPDaemon) {
	self.info.mode = "STREAM"
	log.Println("Incoming nntp connection from", self.conn.RemoteAddr())
	// send welcome
	self.SendLine("200 ayy lmao we are SRNd2, posting allowed")
	for {
		line := self.ReadLine()
    if len(line) == 0 {
			break
		}
		// parse line

		_line := strings.Replace(line, "\n", "", -1)
		_line = strings.Replace(_line, "\r", "", -1)
		commands := strings.Split(_line, " ")
		cmd := strings.ToUpper(commands[0])

		// capabilities command
		if cmd == "CAPABILITIES" {
			self.sendCapabilities()
		} else if cmd == "MODE" { // mode switch
			if len(commands) == 2 {
				mode := strings.ToUpper(commands[1])
				if mode == "READER" {
					self.SendLine("501 no reader mode")
				} else if mode == "STREAM" {
					self.info.mode = mode
					self.SendLine("203 stream as desired")
				} else {
					self.SendLine("501 unknown mode")
				}
			} else {
				self.SendLine("500 syntax error")
			}
		} else if self.info.mode == "STREAM" { // we are in stream mode
			if cmd == "TAKETHIS" {
				if len(commands) == 2 {
					article := commands[1]
					if ValidMessageID(article) {
						file := d.store.OpenFile(article)
						for {
							line := self.ReadLine()
							// unexpected close
							if len(line) == 0 {
								log.Fatal(self.conn.RemoteAddr(), "unexpectedly closed connection")
							}
							// done reading
							if line == ".\r\n" {
								break
							} else {
								line = strings.Replace(line, "\r", "", -1)
								file.Write([]byte(line))
							}
						}
						file.Close()
						// the send was good
						// tell them
						self.SendLine("239 "+article)
						d.infeed <- article
					}
				}
			}
			if cmd == "CHECK" {
				if len(commands) == 2 {
					if ! ValidMessageID(commands[1]) {
						self.SendLine("501 bad message id")
						continue
					}
					article := commands[1]
					if d.store.HasArticle(article) {
						self.Send("435 ")
						self.Send(commands[1])
						self.SendLine(" we have this article")
					} else {
						self.Send("238 ")
						self.Send(commands[1])
						self.SendLine(" we want this article please give it")
					}
				}
			}
		}
	}
	self.Close()
}

func (self *NNTPConnection) sendCapabilities() {
	self.SendLine("101 we can do stuff")
	self.SendLine("VERSION 2")
	self.SendLine("IMPLEMENTATION srndv2 better than SRNd")
	self.SendLine("STREAMING")
	self.SendLine(".")
}

func (self *NNTPConnection) Quit() {
	if ! self.inbound {
		self.SendLine("QUIT")
		_ = self.ReadLine()
	}
	self.Close()
}

func (self *NNTPConnection) ReadLine() string {
	line, err := self.reader.ReadString('\n')
	if err != nil {
		return ""
	}
	//line = strings.Replace(line, "\n", "", -1)
	//line = strings.Replace(line, "\r", "", -1)
	if self.debug {
		log.Println(self.conn.RemoteAddr(), "recv line", line)
	}
	return line
}

// send a line
func (self *NNTPConnection) SendLine(line string) {
	if self.debug {
		log.Println(self.conn.RemoteAddr(), "send line", line)
	}
	self.Send(line+"\r\n")
}

// send data
func (self *NNTPConnection) Send(data string) {

	self.conn.Write([]byte(data))
}

// send data
func (self *NNTPConnection) SendBytes(data []byte) {
	self.conn.Write(data)
}

// close the connection
func (self *NNTPConnection) Close() {
	err := self.conn.Close()
	if err != nil {
		log.Println(self.conn.RemoteAddr(), err)
	}
	log.Println(self.conn.RemoteAddr(), "Closed Connection")
}
<commit_msg>check for errors on send in nntp handlers<commit_after>//
// nntp.go
//
package main

import (
	"bufio"
	"bytes"
	"io/ioutil"
	"log"
	"net"
	"strings"
)

type ConnectionInfo struct {
	mode string
	newsgroup string
	allowsPosting bool
	supportsStream bool
}

type NNTPConnection struct {
	conn net.Conn
	reader *bufio.Reader
	inbound bool
	debug bool
	info *ConnectionInfo
	policy *FeedPolicy
	send chan *NNTPMessage
}

func (self *NNTPConnection) HandleOutbound(d *NNTPDaemon) {
	var err error
	line := self.ReadLine()
	self.info.allowsPosting = strings.HasPrefix(line, "200 ")
	// they allow posting
	// send capabilities command
	err = self.SendLine("CAPABILITIES")

	// get capabilites
	for {
		line = strings.ToLower(self.ReadLine())
		if line == ".\r\n" {
			// done reading capabilities
			break
		}
		if line == "streaming\r\n" {
			self.info.supportsStream = true
		} else if line == "postihavestreaming\r\n" {
			self.info.supportsStream = true
		}
	}

	// if they support streaming and allow posting continue
	// otherwise quit
	if ! self.info.supportsStream || ! self.info.allowsPosting {
		if self.debug {
			log.Println(self.info.supportsStream, self.info.allowsPosting)
		}

		self.Quit()
		return
	}
	err = self.SendLine("MODE STREAM")
	if err != nil {
		return
	}
	line = self.ReadLine()
	if strings.HasPrefix(line, "203 ") {
		self.info.mode = "stream"
		log.Println("streaming mode activated")
	} else {
		self.Quit()
		return
	}
	// mainloop
	for  {
		// poll for new message
		message := <- self.send
		// check if we allow it
		if ! self.policy.AllowsNewsgroup(message.Newsgroup) {
			log.Println("not federating article", message.MessageID, "beause it's in", message.Newsgroup)
			continue
		}
		log.Println("send article")
		// send check
		err = self.Send("CHECK ")
		err = self.SendLine(message.MessageID)
		line = self.ReadLine()
		if strings.HasPrefix(line, "238 ") {
			// accepted
			// send it
			err = self.Send("TAKETHIS ")
			err = self.SendLine(message.MessageID)
			// load file
			data, err := ioutil.ReadFile(d.store.GetFilename(message.MessageID))
			if err != nil {
				log.Fatal("failed to read article", message.MessageID)
			}
			// split into lines
			parts := bytes.Split(data,[]byte{'\n'})
			// for each line send it
			for idx := range parts {
				ba := parts[idx]
				err = self.SendBytes(ba)
				err = self.Send("\r\n")
			}
			// send delimiter
			err = self.SendLine(".")
			if err != nil {
				log.Println("failed to send")
				self.Quit()
				return
			}
			// check for success / fail
			line := self.ReadLine()
			if strings.HasPrefix(line, "239 ") {
				log.Println("Article", message.MessageID, "sent")
			} else {
				log.Println("Article", message.MessageID, "failed to send", line)
			}
			// continue
			continue
		} else if strings.HasPrefix(line, "435 ") {
			// already have it
			if self.debug {
				log.Println(message.MessageID, "already owned")
			}
		} else if strings.HasPrefix(line, "437 ") {
			// article banned
			log.Println(message.MessageID, "was banned")
		}
		if err != nil {
			self.Quit()
			log.Println("failure in outfeed", err)
		}
	}
}

// handle inbound connection
func (self *NNTPConnection) HandleInbound(d *NNTPDaemon) {
	var err error
	self.info.mode = "STREAM"
	log.Println("Incoming nntp connection from", self.conn.RemoteAddr())
	// send welcome
	self.SendLine("200 ayy lmao we are SRNd2, posting allowed")
	for {
		if err != nil {
			log.Println("failure in infeed", err)
			self.Quit()
			return
		}
		line := self.ReadLine()
    	if len(line) == 0 {
			break
		}
		// parse line

		_line := strings.Replace(line, "\n", "", -1)
		_line = strings.Replace(_line, "\r", "", -1)
		commands := strings.Split(_line, " ")
		cmd := strings.ToUpper(commands[0])

		// capabilities command
		if cmd == "CAPABILITIES" {
			self.sendCapabilities()
		} else if cmd == "MODE" { // mode switch
			if len(commands) == 2 {
				mode := strings.ToUpper(commands[1])
				if mode == "READER" {
					self.SendLine("501 no reader mode")
				} else if mode == "STREAM" {
					self.info.mode = mode
					self.SendLine("203 stream as desired")
				} else {
					self.SendLine("501 unknown mode")
				}
			} else {
				self.SendLine("500 syntax error")
			}
		} else if self.info.mode == "STREAM" { // we are in stream mode
			if cmd == "TAKETHIS" {
				if len(commands) == 2 {
					article := commands[1]
					if ValidMessageID(article) {
						file := d.store.OpenFile(article)
						for {
							line := self.ReadLine()
							// unexpected close
							if len(line) == 0 {
								log.Fatal(self.conn.RemoteAddr(), "unexpectedly closed connection")
							}
							// done reading
							if line == ".\r\n" {
								break
							} else {
								line = strings.Replace(line, "\r", "", -1)
								file.Write([]byte(line))
							}
						}
						file.Close()
						// the send was good
						// tell them
						self.SendLine("239 "+article)
						d.infeed <- article
					}
				}
			}
			if cmd == "CHECK" {
				if len(commands) == 2 {
					if ! ValidMessageID(commands[1]) {
						self.SendLine("501 bad message id")
						continue
					}
					article := commands[1]
					if d.store.HasArticle(article) {
						self.Send("435 ")
						self.Send(commands[1])
						self.SendLine(" we have this article")
					} else {
						self.Send("238 ")
						self.Send(commands[1])
						self.SendLine(" we want this article please give it")
					}
				}
			}
		}
	}
	self.Close()
}

func (self *NNTPConnection) sendCapabilities() {
	self.SendLine("101 we can do stuff")
	self.SendLine("VERSION 2")
	self.SendLine("IMPLEMENTATION srndv2 better than SRNd")
	self.SendLine("STREAMING")
	self.SendLine(".")
}

func (self *NNTPConnection) Quit() {
	if ! self.inbound {
		self.SendLine("QUIT")
		_ = self.ReadLine()
	}
	self.Close()
}

func (self *NNTPConnection) ReadLine() string {
	line, err := self.reader.ReadString('\n')
	if err != nil {
		return ""
	}
	//line = strings.Replace(line, "\n", "", -1)
	//line = strings.Replace(line, "\r", "", -1)
	if self.debug {
		log.Println(self.conn.RemoteAddr(), "recv line", line)
	}
	return line
}

// send a line
func (self *NNTPConnection) SendLine(line string) error {
	if self.debug {
		log.Println(self.conn.RemoteAddr(), "send line", line)
	}
	return self.Send(line+"\r\n")
}

// send data
func (self *NNTPConnection) Send(data string) error {
	_, err := self.conn.Write([]byte(data))
	return err
}

// send data
func (self *NNTPConnection) SendBytes(data []byte) error {
	_ , err := self.conn.Write(data)
	return err
}

// close the connection
func (self *NNTPConnection) Close() {
	err := self.conn.Close()
	if err != nil {
		log.Println(self.conn.RemoteAddr(), err)
	}
	log.Println(self.conn.RemoteAddr(), "Closed Connection")
}
<|endoftext|>