<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	"github.com/mlafeldt/chef-runner/chef/cookbook"
	"github.com/mlafeldt/chef-runner/chef/omnibus"
	"github.com/mlafeldt/chef-runner/chef/runlist"
	"github.com/mlafeldt/chef-runner/cli"
	"github.com/mlafeldt/chef-runner/driver"
	"github.com/mlafeldt/chef-runner/driver/kitchen"
	"github.com/mlafeldt/chef-runner/driver/local"
	"github.com/mlafeldt/chef-runner/driver/ssh"
	"github.com/mlafeldt/chef-runner/driver/vagrant"
	"github.com/mlafeldt/chef-runner/log"
	"github.com/mlafeldt/chef-runner/provisioner"
	"github.com/mlafeldt/chef-runner/provisioner/chefsolo"
	"github.com/mlafeldt/chef-runner/resolver"
)

const (
	// SandboxPath is the path to the local sandbox directory where
	// chef-runner stores files that will be uploaded to a machine.
	SandboxPath = ".chef-runner/sandbox"

	// RootPath is the path on the machine where files from SandboxPath
	// will be uploaded to.
	RootPath = "/tmp/chef-runner"
)

func abort(v ...interface{}) {
	log.Error(v...)
	os.Exit(1)
}

func findDriver(flags *cli.Flags) (driver.Driver, error) {
	if flags.Host != "" {
		return ssh.NewDriver(flags.Host, flags.SSHOptions, flags.RsyncOptions)
	}
	if flags.Kitchen != "" {
		return kitchen.NewDriver(flags.Kitchen, flags.SSHOptions, flags.RsyncOptions)
	}
	if flags.Local {
		return local.NewDriver()
	}
	return vagrant.NewDriver(flags.Machine, flags.SSHOptions, flags.RsyncOptions)
}

func uploadFiles(drv driver.Driver) error {
	log.Info("Uploading local files to machine. This may take a while...")
	log.Debugf("Uploading files from %s to %s on machine\n",
		SandboxPath, RootPath)
	return drv.Upload(RootPath, SandboxPath+"/")
}

func installChef(drv driver.Driver, installer omnibus.Installer) error {
	installCmd := installer.Command()
	if len(installCmd) == 0 {
		log.Info("Skipping installation of Chef")
		return nil
	}
	log.Info("Installing Chef")
	return drv.RunCommand(installCmd)
}

func runChef(drv driver.Driver, p provisioner.Provisioner) error {
	log.Infof("Running Chef using %s\n", drv)
	return drv.RunCommand(p.Command())
}

func main() {
	startTime := time.Now()

	log.SetLevel(cli.LogLevel())

	flags, err := cli.ParseFlags(os.Args[1:])
	if err != nil {
		abort(err)
	}

	log.UseColor = flags.Color

	if flags.ShowVersion {
		fmt.Printf("chef-runner %s %s %s\n", VersionString(),
			TargetString(), GoVersionString())
		os.Exit(0)
	}

	log.Infof("Starting chef-runner (%s %s)\n", VersionString(), TargetString())

	var attributes string
	if flags.JSONFile != "" {
		data, err := ioutil.ReadFile(flags.JSONFile)
		if err != nil {
			abort(err)
		}
		attributes = string(data)
	}

	// 1) Run default recipe if no recipes are passed
	// 2) Use run list from JSON file if present, overriding 1)
	// 3) Use run list from command line if present, overriding 1) and 2)
	recipes := flags.Recipes
	if len(recipes) == 0 {
		// TODO: parse actual JSON data
		if strings.Contains(attributes, "run_list") {
			log.Infof("Using run list from %s\n", flags.JSONFile)
		} else {
			recipes = []string{"::default"}
		}
	}

	var runList []string
	if len(recipes) > 0 {
		cb, err := cookbook.NewCookbook(".")
		if err != nil {
			abort(err)
		}
		log.Debugf("Cookbook = %s\n", cb)

		if runList, err = runlist.Build(recipes, cb.Name); err != nil {
			abort(err)
		}
		log.Infof("Run list is %s\n", runList)
	}

	var p provisioner.Provisioner
	p = chefsolo.Provisioner{
		RunList:     runList,
		Attributes:  attributes,
		Format:      flags.Format,
		LogLevel:    flags.LogLevel,
		SandboxPath: SandboxPath,
		RootPath:    RootPath,
		Sudo:        flags.Sudo,
	}
	log.Debugf("Provisioner = %+v\n", p)

	installer := omnibus.Installer{
		ChefVersion: flags.ChefVersion,
		SandboxPath: SandboxPath,
		RootPath:    RootPath,
		Sudo:        flags.Sudo,
	}
	log.Debugf("Installer = %+v\n", installer)

	log.Info("Preparing local files")

	log.Debug("Creating local sandbox in", SandboxPath)
	if err := os.MkdirAll(SandboxPath, 0755); err != nil {
		abort(err)
	}

	if err := p.PrepareFiles(); err != nil {
		abort(err)
	}

	cookbookPath := path.Join(SandboxPath, "cookbooks")
	if err := resolver.Resolve(flags.Resolver, cookbookPath); err != nil {
		abort(err)
	}

	if err := installer.PrepareFiles(); err != nil {
		abort(err)
	}

	drv, err := findDriver(flags)
	if err != nil {
		abort(err)
	}

	if err := uploadFiles(drv); err != nil {
		abort(err)
	}

	if err := installChef(drv, installer); err != nil {
		abort(err)
	}

	if err := runChef(drv, p); err != nil {
		abort(err)
	}

	log.Info("chef-runner finished in", time.Now().Sub(startTime))
}
<commit_msg>Add canonical import path<commit_after>package main // import "github.com/mlafeldt/chef-runner"

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	"github.com/mlafeldt/chef-runner/chef/cookbook"
	"github.com/mlafeldt/chef-runner/chef/omnibus"
	"github.com/mlafeldt/chef-runner/chef/runlist"
	"github.com/mlafeldt/chef-runner/cli"
	"github.com/mlafeldt/chef-runner/driver"
	"github.com/mlafeldt/chef-runner/driver/kitchen"
	"github.com/mlafeldt/chef-runner/driver/local"
	"github.com/mlafeldt/chef-runner/driver/ssh"
	"github.com/mlafeldt/chef-runner/driver/vagrant"
	"github.com/mlafeldt/chef-runner/log"
	"github.com/mlafeldt/chef-runner/provisioner"
	"github.com/mlafeldt/chef-runner/provisioner/chefsolo"
	"github.com/mlafeldt/chef-runner/resolver"
)

const (
	// SandboxPath is the path to the local sandbox directory where
	// chef-runner stores files that will be uploaded to a machine.
	SandboxPath = ".chef-runner/sandbox"

	// RootPath is the path on the machine where files from SandboxPath
	// will be uploaded to.
	RootPath = "/tmp/chef-runner"
)

func abort(v ...interface{}) {
	log.Error(v...)
	os.Exit(1)
}

func findDriver(flags *cli.Flags) (driver.Driver, error) {
	if flags.Host != "" {
		return ssh.NewDriver(flags.Host, flags.SSHOptions, flags.RsyncOptions)
	}
	if flags.Kitchen != "" {
		return kitchen.NewDriver(flags.Kitchen, flags.SSHOptions, flags.RsyncOptions)
	}
	if flags.Local {
		return local.NewDriver()
	}
	return vagrant.NewDriver(flags.Machine, flags.SSHOptions, flags.RsyncOptions)
}

func uploadFiles(drv driver.Driver) error {
	log.Info("Uploading local files to machine. This may take a while...")
	log.Debugf("Uploading files from %s to %s on machine\n",
		SandboxPath, RootPath)
	return drv.Upload(RootPath, SandboxPath+"/")
}

func installChef(drv driver.Driver, installer omnibus.Installer) error {
	installCmd := installer.Command()
	if len(installCmd) == 0 {
		log.Info("Skipping installation of Chef")
		return nil
	}
	log.Info("Installing Chef")
	return drv.RunCommand(installCmd)
}

func runChef(drv driver.Driver, p provisioner.Provisioner) error {
	log.Infof("Running Chef using %s\n", drv)
	return drv.RunCommand(p.Command())
}

func main() {
	startTime := time.Now()

	log.SetLevel(cli.LogLevel())

	flags, err := cli.ParseFlags(os.Args[1:])
	if err != nil {
		abort(err)
	}

	log.UseColor = flags.Color

	if flags.ShowVersion {
		fmt.Printf("chef-runner %s %s %s\n", VersionString(),
			TargetString(), GoVersionString())
		os.Exit(0)
	}

	log.Infof("Starting chef-runner (%s %s)\n", VersionString(), TargetString())

	var attributes string
	if flags.JSONFile != "" {
		data, err := ioutil.ReadFile(flags.JSONFile)
		if err != nil {
			abort(err)
		}
		attributes = string(data)
	}

	// 1) Run default recipe if no recipes are passed
	// 2) Use run list from JSON file if present, overriding 1)
	// 3) Use run list from command line if present, overriding 1) and 2)
	recipes := flags.Recipes
	if len(recipes) == 0 {
		// TODO: parse actual JSON data
		if strings.Contains(attributes, "run_list") {
			log.Infof("Using run list from %s\n", flags.JSONFile)
		} else {
			recipes = []string{"::default"}
		}
	}

	var runList []string
	if len(recipes) > 0 {
		cb, err := cookbook.NewCookbook(".")
		if err != nil {
			abort(err)
		}
		log.Debugf("Cookbook = %s\n", cb)

		if runList, err = runlist.Build(recipes, cb.Name); err != nil {
			abort(err)
		}
		log.Infof("Run list is %s\n", runList)
	}

	var p provisioner.Provisioner
	p = chefsolo.Provisioner{
		RunList:     runList,
		Attributes:  attributes,
		Format:      flags.Format,
		LogLevel:    flags.LogLevel,
		SandboxPath: SandboxPath,
		RootPath:    RootPath,
		Sudo:        flags.Sudo,
	}
	log.Debugf("Provisioner = %+v\n", p)

	installer := omnibus.Installer{
		ChefVersion: flags.ChefVersion,
		SandboxPath: SandboxPath,
		RootPath:    RootPath,
		Sudo:        flags.Sudo,
	}
	log.Debugf("Installer = %+v\n", installer)

	log.Info("Preparing local files")

	log.Debug("Creating local sandbox in", SandboxPath)
	if err := os.MkdirAll(SandboxPath, 0755); err != nil {
		abort(err)
	}

	if err := p.PrepareFiles(); err != nil {
		abort(err)
	}

	cookbookPath := path.Join(SandboxPath, "cookbooks")
	if err := resolver.Resolve(flags.Resolver, cookbookPath); err != nil {
		abort(err)
	}

	if err := installer.PrepareFiles(); err != nil {
		abort(err)
	}

	drv, err := findDriver(flags)
	if err != nil {
		abort(err)
	}

	if err := uploadFiles(drv); err != nil {
		abort(err)
	}

	if err := installChef(drv, installer); err != nil {
		abort(err)
	}

	if err := runChef(drv, p); err != nil {
		abort(err)
	}

	log.Info("chef-runner finished in", time.Now().Sub(startTime))
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/dynport/dgtk/cli"
	"github.com/phrase/phraseapp-go/phraseapp"
)

func main() {
	Run()
}

func Run() {
	validateVersion()

	cfg, err := phraseapp.ReadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(2)
	}

	err = router(cfg).RunWithArgs()
	switch err {
	case cli.ErrorHelpRequested, cli.ErrorNoRoute:
		os.Exit(1)
	case nil:
		os.Exit(0)
	default:
		printErr(err)
		os.Exit(1)
	}
}

const PHRASEAPP_VERSION_TMP_FILE = "/tmp/.phraseapp.version"

func validateVersion() {
	var version string
	stat, err := os.Stat(PHRASEAPP_VERSION_TMP_FILE)
	if PHRASEAPP_CLIENT_VERSION == "test" {
		fmt.Fprintf(os.Stderr, "You're running a development version of the PhraseApp CLI client!\n\n")
		return
	} else if os.IsNotExist(err) || time.Since(stat.ModTime()) > time.Hour {
		// fetch new version, if not done so or over an hour ago
		version, err = getCurrentVersion()
		if err == nil { // persist the version for the next hour
			err = ioutil.WriteFile(PHRASEAPP_VERSION_TMP_FILE, []byte(version), 0600)
		}
	} else if err == nil {
		// otherwise load the version (fetched less than an hour ago) from the temp file
		var buf []byte
		buf, err = ioutil.ReadFile(PHRASEAPP_VERSION_TMP_FILE)
		if err == nil {
			version = string(buf)
		}
	}

	if err == nil && version != PHRASEAPP_CLIENT_VERSION {
		fmt.Fprintf(os.Stderr, "Please consider updating the PhraseApp CLI client (%s < %s)\nSee https://phraseapp.com/en/cli\n\n", PHRASEAPP_CLIENT_VERSION, version)
	}
}

func getCurrentVersion() (string, error) {
	req, err := http.NewRequest("HEAD", "https://github.com/phrase/phraseapp-client/releases/latest", nil)
	if err != nil {
		return "", err
	}

	transport := http.Transport{}
	resp, err := transport.RoundTrip(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close() // body is empty as it is only a HEAD request

	if resp.StatusCode != 302 {
		return "", fmt.Errorf("failed to request the file")
	}

	url, err := resp.Location()
	if err != nil {
		return "", err
	}

	segments := strings.Split(url.Path, "/")
	for i := len(segments) - 1; i >= 0; i-- {
		if segments[i] != "" {
			return segments[i], nil
		}
	}
	return "", fmt.Errorf("no valid version segment found")
}
<commit_msg>router: add error return to router creation<commit_after>package main

import (
	"os"

	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/dynport/dgtk/cli"
	"github.com/phrase/phraseapp-go/phraseapp"
)

func main() {
	Run()
}

func Run() {
	validateVersion()

	cfg, err := phraseapp.ReadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(2)
	}

	r, err := router(cfg)
	if err != nil {
		printErr(err)
		os.Exit(3)
	}

	switch err := r.RunWithArgs(); err {
	case cli.ErrorHelpRequested, cli.ErrorNoRoute:
		os.Exit(1)
	case nil:
		os.Exit(0)
	default:
		printErr(err)
		os.Exit(1)
	}
}

const PHRASEAPP_VERSION_TMP_FILE = "/tmp/.phraseapp.version"

func validateVersion() {
	var version string
	stat, err := os.Stat(PHRASEAPP_VERSION_TMP_FILE)
	if PHRASEAPP_CLIENT_VERSION == "test" {
		fmt.Fprintf(os.Stderr, "You're running a development version of the PhraseApp CLI client!\n\n")
		return
	} else if os.IsNotExist(err) || time.Since(stat.ModTime()) > time.Hour {
		// fetch new version, if not done so or over an hour ago
		version, err = getCurrentVersion()
		if err == nil { // persist the version for the next hour
			err = ioutil.WriteFile(PHRASEAPP_VERSION_TMP_FILE, []byte(version), 0600)
		}
	} else if err == nil {
		// otherwise load the version (fetched less than an hour ago) from the temp file
		var buf []byte
		buf, err = ioutil.ReadFile(PHRASEAPP_VERSION_TMP_FILE)
		if err == nil {
			version = string(buf)
		}
	}

	if err == nil && version != PHRASEAPP_CLIENT_VERSION {
		fmt.Fprintf(os.Stderr, "Please consider updating the PhraseApp CLI client (%s < %s)\nSee https://phraseapp.com/en/cli\n\n", PHRASEAPP_CLIENT_VERSION, version)
	}
}

func getCurrentVersion() (string, error) {
	req, err := http.NewRequest("HEAD", "https://github.com/phrase/phraseapp-client/releases/latest", nil)
	if err != nil {
		return "", err
	}

	transport := http.Transport{}
	resp, err := transport.RoundTrip(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close() // body is empty as it is only a HEAD request

	if resp.StatusCode != 302 {
		return "", fmt.Errorf("failed to request the file")
	}

	url, err := resp.Location()
	if err != nil {
		return "", err
	}

	segments := strings.Split(url.Path, "/")
	for i := len(segments) - 1; i >= 0; i-- {
		if segments[i] != "" {
			return segments[i], nil
		}
	}
	return "", fmt.Errorf("no valid version segment found")
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/genuinetools/pkg/cli"
	"github.com/genuinetools/weather/forecast"
	"github.com/genuinetools/weather/geocode"
	"github.com/genuinetools/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.jessfraz.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	server       string
	client       bool

	geo geocode.Geocode
)

//go:generate go run icons/generate.go

func main() {
	// Create a new cli program.
	p := cli.NewProgram()
	p.Name = "weather"
	p.Description = "Weather forecast via the command line"

	// Set the GitCommit and Version.
	p.GitCommit = version.GITCOMMIT
	p.Version = version.VERSION

	// Build the list of available commands.
	p.Commands = []cli.Command{
		&serverCommand{},
	}

	// Setup the global flags.
	p.FlagSet = flag.NewFlagSet("global", flag.ExitOnError)
	p.FlagSet.StringVar(&location, "location", "", "Location to get the weather")
	p.FlagSet.StringVar(&location, "l", "", "Location to get the weather (shorthand)")

	p.FlagSet.BoolVar(&client, "client", false, "Get location for the ssh client")
	p.FlagSet.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")

	p.FlagSet.StringVar(&units, "units", "auto", "System of units (e.g. auto, us, si, ca, uk2)")
	p.FlagSet.StringVar(&units, "u", "auto", "System of units (shorthand) (e.g. auto, us, si, ca, uk2)")

	p.FlagSet.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	p.FlagSet.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")

	p.FlagSet.IntVar(&days, "days", 0, "No. of days to get forecast")
	p.FlagSet.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")

	p.FlagSet.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	p.FlagSet.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	p.FlagSet.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hours")

	// Set the before function.
	p.Before = func(ctx context.Context) error {
		if len(server) < 1 {
			return errors.New("Please enter a Weather API server uri or leave blank to use the default")
		}

		return nil
	}

	// Set the main program action.
	p.Action = func(ctx context.Context, args []string) error {
		var err error
		if location == "" {
			sshConn := os.Getenv("SSH_CONNECTION")
			if client && len(sshConn) > 0 {
				// use their ssh connection to locate them
				ipports := strings.Split(sshConn, " ")
				geo, err = geocode.IPLocate(ipports[0])
				if err != nil {
					printError(err)
				}

			} else {
				// auto locate them
				geo, err = geocode.Autolocate()
				if err != nil {
					printError(err)
				}

				if geo.Latitude == 0 || geo.Longitude == 0 {
					printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
				}
			}
		} else {
			// get geolocation data for the given location
			geo, err = geocode.Locate(location, server)
			if err != nil {
				printError(err)
			}
		}

		if geo.Latitude == 0 || geo.Longitude == 0 {
			printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
		}

		data := forecast.Request{
			Latitude:  geo.Latitude,
			Longitude: geo.Longitude,
			Units:     units,
			Exclude:   []string{"minutely"},
		}
		if noForecast {
			data.Exclude = append(data.Exclude, "hourly")
		}

		fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
		if err != nil {
			printError(err)
		}

		if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
			printError(err)
		}

		if days > 0 {
			forecast.PrintDaily(fc, days)
		}

		return nil
	}

	// Run our program.
	p.Run()
}

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}
<commit_msg>adds JSON output option (#60)<commit_after>package main

import (
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/genuinetools/pkg/cli"
	"github.com/genuinetools/weather/forecast"
	"github.com/genuinetools/weather/geocode"
	"github.com/genuinetools/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.jessfraz.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	jsonOut      bool
	server       string
	client       bool

	geo geocode.Geocode
)

//go:generate go run icons/generate.go

func main() {
	// Create a new cli program.
	p := cli.NewProgram()
	p.Name = "weather"
	p.Description = "Weather forecast via the command line"

	// Set the GitCommit and Version.
	p.GitCommit = version.GITCOMMIT
	p.Version = version.VERSION

	// Build the list of available commands.
	p.Commands = []cli.Command{
		&serverCommand{},
	}

	// Setup the global flags.
	p.FlagSet = flag.NewFlagSet("global", flag.ExitOnError)
	p.FlagSet.StringVar(&location, "location", "", "Location to get the weather")
	p.FlagSet.StringVar(&location, "l", "", "Location to get the weather (shorthand)")

	p.FlagSet.BoolVar(&client, "client", false, "Get location for the ssh client")
	p.FlagSet.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")

	p.FlagSet.StringVar(&units, "units", "auto", "System of units (e.g. auto, us, si, ca, uk2)")
	p.FlagSet.StringVar(&units, "u", "auto", "System of units (shorthand) (e.g. auto, us, si, ca, uk2)")

	p.FlagSet.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	p.FlagSet.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")

	p.FlagSet.IntVar(&days, "days", 0, "No. of days to get forecast")
	p.FlagSet.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")

	p.FlagSet.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	p.FlagSet.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	p.FlagSet.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hours")

	p.FlagSet.BoolVar(&jsonOut, "json", false, "Prints the raw JSON API response")

	// Set the before function.
	p.Before = func(ctx context.Context) error {
		if len(server) < 1 {
			return errors.New("Please enter a Weather API server uri or leave blank to use the default")
		}

		return nil
	}

	// Set the main program action.
	p.Action = func(ctx context.Context, args []string) error {
		var err error
		if location == "" {
			sshConn := os.Getenv("SSH_CONNECTION")
			if client && len(sshConn) > 0 {
				// use their ssh connection to locate them
				ipports := strings.Split(sshConn, " ")
				geo, err = geocode.IPLocate(ipports[0])
				if err != nil {
					printError(err)
				}

			} else {
				// auto locate them
				geo, err = geocode.Autolocate()
				if err != nil {
					printError(err)
				}

				if geo.Latitude == 0 || geo.Longitude == 0 {
					printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
				}
			}
		} else {
			// get geolocation data for the given location
			geo, err = geocode.Locate(location, server)
			if err != nil {
				printError(err)
			}
		}

		if geo.Latitude == 0 || geo.Longitude == 0 {
			printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
		}

		data := forecast.Request{
			Latitude:  geo.Latitude,
			Longitude: geo.Longitude,
			Units:     units,
			Exclude:   []string{"minutely"},
		}
		if noForecast {
			data.Exclude = append(data.Exclude, "hourly")
		}

		fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
		if err != nil {
			printError(err)
		}

		if jsonOut {
			jsn, err := json.Marshal(&fc)
			if err != nil {
				printError(err)
			}

			fmt.Println(string(jsn))
			return nil
		}

		if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
			printError(err)
		}

		if days > 0 {
			forecast.PrintDaily(fc, days)
		}

		return nil
	}

	// Run our program.
	p.Run()
}

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"io"
	"log"
	"mime"
	"net/mail"
	"net/smtp"
	"os"
	"strconv"

	message "github.com/matsuev/go-message"
	charset "github.com/matsuev/go-message/charset"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// Перенаправление логов в файл
	// создать файл лога, установить права доступа
	// l, err := os.OpenFile("./klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// l, err := os.OpenFile("/var/log/klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// logFatal(err)
	// defer l.Close()

	// log.SetOutput(l)

	// Заголовки исходного сообщения,
	// которые нужно оставить
	hh := []string{
		"MIME-Version",
		"Message-Id",
		"Content-Type",
		"Content-Transfer-Encoding",
		"In-Reply-To",
		"References",
		// "Subject",
	}

	// r, err := os.Open("./testmessage.eml")
	// if err != nil {
	// 	log.Fatal(err)
	// }
	// defer r.Close()

	// Читаем сообщение из стандартного ввода
	msg, err := message.Read(os.Stdin)
	// msg, err := message.Read(r)
	logFatal(err)
	log.Println("New message accepted...")

	// Разбор заголовков сообщения
	to, err := getMailHeader("To", msg.Header)
	logFatal(err)
	log.Printf("To: %s <%s>\n", to.Name, to.Address)

	from, err := getMailHeader("From", msg.Header)
	logFatal(err)
	log.Printf("From: %s <%s>\n", from.Name, from.Address)

	hSubject, err := charset.DecodeHeader(msg.Header.Get("Subject"))
	logFatal(err)

	subj := mime.BEncoding.Encode("utf-8", hSubject)

	if to.Address == "" || from.Address == "" {
		log.Fatalln("Empty address. Reject message.")
	}

	// Сокдинение с сервером БД
	db, err := sql.Open("mysql", "klshmail:euXoe8uSha1xu4sh@/klshmail?charset=utf8")
	logFatal(err)

	// Проверка соединения с сервером БД
	err = db.Ping()
	logFatal(err)

	// Запрос данных о списке рассылки
	var lid uint64
	var lprefix string

	err = db.QueryRow(`
		SELECT list.id, list.prefix
		FROM list
		WHERE LCASE(list.email)=TRIM(LCASE(?))
		AND list.active
		`, to.Address).Scan(&lid, &lprefix)
	if err != nil {
		log.Println("No list with address:", to.Address)
		os.Exit(0)
	}

	// Запрос на проверку прав пользователя на отправку сообщений в список
	var uid uint64
	err = db.QueryRow(`
		SELECT user.id
		FROM user
		INNER JOIN user_list
		ON (user_list.lid=?
			AND user.id=user_list.uid
			AND user_list.canwrite
		)
		WHERE LCASE(user.email)=TRIM(LCASE(?))
		AND user.active
		`, lid, from.Address).Scan(&uid)
	if err != nil {
		log.Println("User", from.Address, "can't send messages to", to.Address)
		os.Exit(0)
	}

	// Формирование заголовков нового сообщения
	newHeader := make(message.Header)
	for _, hk := range hh {
		if hv := msg.Header.Get(hk); hv != "" {
			newHeader.Set(hk, hv)
		}
	}

	sender := new(mail.Address)
	sender.Name = from.Name
	sender.Address = from.Address

	from.Name = fmt.Sprintf("%s", lprefix)
	from.Address = to.Address

	newHeader.Set("From", from.String())
	newHeader.Set("Reply-To", to.Address)
	newHeader.Set("Subject", subj)
	newHeader.Set("X-KLSH-Sender", strconv.FormatUint(uid, 10))

	var b bytes.Buffer
	w, err := message.CreateWriter(&b, newHeader)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Close()

	if err := transform(w, msg, sender); err != nil {
		log.Fatal(err)
	}

	// Подключение к SMTP серверу
	c, err := smtp.Dial("127.0.0.1:25")
	if err != nil {
		log.Println("SMTP connection error")
		log.Fatal(err)
	}
	defer c.Close()

	// Заголовки для отправки
	c.Mail(to.Address)
	c.Rcpt(fmt.Sprintf("%v@klshmail", lid))

	wc, err := c.Data()
	logFatal(err)
	defer wc.Close()

	// Отправка сообщения
	br := bytes.NewReader(b.Bytes())
	if _, err = io.Copy(wc, br); err != nil {
		log.Println("SMTP send body error")
		log.Fatalln(err)
	}

	// fmt.Println(b.String())

	// Завершение работы
	log.Println("Message processing done.")

}

func logFatal(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

const senderHtml string = `<p><b>Сообщение от:</b> %s <<a href="mailto:%s">%s</a>><p>`
const senderPlain string = "| Сообщение от:  %s <%s>\n——\n\n"

func transform(w *message.Writer, e *message.Entity, sender *mail.Address) error {
	if mr := e.MultipartReader(); mr != nil {
		// This is a multipart entity, transform each of its parts
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return err
			}

			fmt.Println(p.Header)

			p.Header.Add("Content-Transfer-Encoding", "base64")
			pw, err := w.CreatePart(p.Header)
			if err != nil {
				return err
			}

			if err := transform(pw, p, sender); err != nil {
				return err
			}

			pw.Close()
		}
		return nil
	} else {
		body := e.Body
		// var newLine string
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/plain") {
		// 	newLine = fmt.Sprintf(senderPlain, sender.Name, sender.Address)
		// }
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/html") {
		// 	newLine = fmt.Sprintf(senderHtml, sender.Name, sender.Address, sender.Address)
		// }
		// body = io.MultiReader(strings.NewReader(newLine), body)

		// rb := make([]byte, 0)
		// io.ReadFull(body, rb)
		//
		// encoder := base64.NewEncoder(base64.StdEncoding, w)
		// _, err := encoder.Write(rb)
		_, err := io.Copy(w, body)
		return err
	}
}

func getMailHeader(k string, h message.Header) (*mail.Address, error) {
	dh, err := charset.DecodeHeader(h.Get(k))
	if err != nil {
		return nil, err
	}

	rh, err := mail.ParseAddress(dh)
	return rh, err
}
<commit_msg>Update main.go<commit_after>package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"io"
	"log"
	"mime"
	"net/mail"
	"net/smtp"
	"os"
	"strconv"
	"strings"

	message "github.com/matsuev/go-message"
	charset "github.com/matsuev/go-message/charset"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// Перенаправление логов в файл
	// создать файл лога, установить права доступа
	// l, err := os.OpenFile("./klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// l, err := os.OpenFile("/var/log/klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// logFatal(err)
	// defer l.Close()

	// log.SetOutput(l)

	// Заголовки исходного сообщения,
	// которые нужно оставить
	hh := []string{
		"MIME-Version",
		"Message-Id",
		"Content-Type",
		"Content-Transfer-Encoding",
		"In-Reply-To",
		"References",
		// "Subject",
	}

	// r, err := os.Open("./testmessage.eml")
	// if err != nil {
	// 	log.Fatal(err)
	// }
	// defer r.Close()

	// Читаем сообщение из стандартного ввода
	msg, err := message.Read(os.Stdin)
	// msg, err := message.Read(r)
	logFatal(err)
	log.Println("New message accepted...")

	// Разбор заголовков сообщения
	to, err := getMailHeader("To", msg.Header)
	logFatal(err)
	log.Printf("To: %s <%s>\n", to.Name, to.Address)

	from, err := getMailHeader("From", msg.Header)
	logFatal(err)
	log.Printf("From: %s <%s>\n", from.Name, from.Address)

	hSubject, err := charset.DecodeHeader(msg.Header.Get("Subject"))
	logFatal(err)

	subj := mime.BEncoding.Encode("utf-8", hSubject)

	if to.Address == "" || from.Address == "" {
		log.Fatalln("Empty address. Reject message.")
	}

	// Сокдинение с сервером БД
	db, err := sql.Open("mysql", "klshmail:euXoe8uSha1xu4sh@/klshmail?charset=utf8")
	logFatal(err)

	// Проверка соединения с сервером БД
	err = db.Ping()
	logFatal(err)

	// Запрос данных о списке рассылки
	var lid uint64
	var lprefix string

	err = db.QueryRow(`
		SELECT list.id, list.prefix
		FROM list
		WHERE LCASE(list.email)=TRIM(LCASE(?))
		AND list.active
		`, to.Address).Scan(&lid, &lprefix)
	if err != nil {
		log.Println("No list with address:", to.Address)
		os.Exit(0)
	}

	// Запрос на проверку прав пользователя на отправку сообщений в список
	var uid uint64
	err = db.QueryRow(`
		SELECT user.id
		FROM user
		INNER JOIN user_list
		ON (user_list.lid=?
			AND user.id=user_list.uid
			AND user_list.canwrite
		)
		WHERE LCASE(user.email)=TRIM(LCASE(?))
		AND user.active
		`, lid, from.Address).Scan(&uid)
	if err != nil {
		log.Println("User", from.Address, "can't send messages to", to.Address)
		os.Exit(0)
	}

	// Формирование заголовков нового сообщения
	newHeader := make(message.Header)
	for _, hk := range hh {
		if hv := msg.Header.Get(hk); hv != "" {
			newHeader.Set(hk, hv)
		}
	}

	sender := new(mail.Address)
	sender.Name = from.Name
	sender.Address = from.Address

	from.Name = fmt.Sprintf("%s", lprefix)
	from.Address = to.Address

	newHeader.Set("From", from.String())
	newHeader.Set("Reply-To", to.Address)
	newHeader.Set("Subject", subj)
	newHeader.Set("X-KLSH-Sender", strconv.FormatUint(uid, 10))

	var b bytes.Buffer
	w, err := message.CreateWriter(&b, newHeader)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Close()

	if err := transform(w, msg, sender); err != nil {
		log.Fatal(err)
	}

	// Подключение к SMTP серверу
	c, err := smtp.Dial("127.0.0.1:25")
	if err != nil {
		log.Println("SMTP connection error")
		log.Fatal(err)
	}
	defer c.Close()

	// Заголовки для отправки
	c.Mail(to.Address)
	c.Rcpt(fmt.Sprintf("%v@klshmail", lid))

	wc, err := c.Data()
	logFatal(err)
	defer wc.Close()

	// Отправка сообщения
	br := bytes.NewReader(b.Bytes())
	if _, err = io.Copy(wc, br); err != nil {
		log.Println("SMTP send body error")
		log.Fatalln(err)
	}

	// fmt.Println(b.String())

	// Завершение работы
	log.Println("Message processing done.")

}

func logFatal(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

const senderHtml string = `<p><b>Сообщение от:</b> %s <<a href="mailto:%s">%s</a>><p>`
const senderPlain string = "| Сообщение от:  %s <%s>\n——\n\n"

func transform(w *message.Writer, e *message.Entity, sender *mail.Address) error {
	if mr := e.MultipartReader(); mr != nil {
		// This is a multipart entity, transform each of its parts
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return err
			}

			fmt.Println(p.Header)

			p.Header.Add("Content-Transfer-Encoding", "base64")
			pw, err := w.CreatePart(p.Header)
			if err != nil {
				return err
			}

			if err := transform(pw, p, sender); err != nil {
				return err
			}

			pw.Close()
		}
		return nil
	} else {
		body := e.Body
		var newLine string
		if strings.HasPrefix(e.Header.Get("Content-Type"), "text/plain") {
			newLine = fmt.Sprintf(senderPlain, sender.Name, sender.Address)
		}
		if strings.HasPrefix(e.Header.Get("Content-Type"), "text/html") {
			newLine = fmt.Sprintf(senderHtml, sender.Name, sender.Address, sender.Address)
		}
		body = io.MultiReader(strings.NewReader(newLine), body)

		// rb := make([]byte, 0)
		// io.ReadFull(body, rb)
		//
		// encoder := base64.NewEncoder(base64.StdEncoding, w)
		// _, err := encoder.Write(rb)
		_, err := io.Copy(w, body)
		return err
	}
}

func getMailHeader(k string, h message.Header) (*mail.Address, error) {
	dh, err := charset.DecodeHeader(h.Get(k))
	if err != nil {
		return nil, err
	}

	rh, err := mail.ParseAddress(dh)
	return rh, err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const VERSION = "0.1.0"

func handleSignals() {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGHUP) // Add syscalls as needed

	// Handle any cleanup
	select {
	case <-ch:
		log.Printf("[INFO] Got a SIGHUP, cleaning up.")
		// Do cleanup here
	}
}

func init() {
	version := flag.Bool("v", false, "prints current project version")

	flag.Usage = func() {
		fmt.Printf("Usage %s [OPTIONS] [name ...]\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}
}

func main() {
	go handleSignals()

	log.Println("[INFO] Starting project")
}
<commit_msg>Add config<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
)

const VERSION = "0.1.0"

var Config string

func handleSignals() {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGHUP) // Add syscalls as needed

	// Handle any cleanup
	select {
	case <-ch:
		log.Printf("[INFO] Got a SIGHUP, cleaning up.")
		// Do cleanup here
	}
}

func init() {
	config := flag.String("config", "config.ini", "path to config file")
	version := flag.Bool("v", false, "prints current project version")

	flag.Usage = func() {
		fmt.Printf("Usage %s [OPTIONS] [name ...]\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	// Instead parse and store as global config object
	Config = *config
}

func main() {
	go handleSignals()

	log.Println("[INFO] Starting project")

	log.Printf("[INFO] Using config file: %s", Config)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"log"
	"net/http"

	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned"
)

var masterHost string

func init() {
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. 'http://127.0.0.1:8080'")
	flag.Parse()
}

type EtcdCluster struct {
	Kind       string            `json:"kind"`
	ApiVersion string            `json:"apiVersion"`
	Metadata   map[string]string `json:"metadata"`
	Size       int               `json:"size"`
}

type Event struct {
	Type   string
	Object EtcdCluster
}

type etcdClusterController struct {
	kclient  *unversioned.Client
	clusters map[string]*Cluster
}

func (c *etcdClusterController) Run() {
	eventCh, errCh := monitorEtcdCluster(c.kclient.RESTClient.Client)
	for {
		select {
		case event := <-eventCh:
			clusterName := event.Object.Metadata["name"]
			switch event.Type {
			case "ADDED":
				c.clusters[clusterName] = newCluster(c.kclient, clusterName, event.Object.Size)
			case "DELETED":
				c.clusters[clusterName].Delete()
				delete(c.clusters, clusterName)
			}
		case err := <-errCh:
			panic(err)
		}
	}
}

func monitorEtcdCluster(httpClient *http.Client) (<-chan *Event, <-chan error) {
	events := make(chan *Event)
	errc := make(chan error, 1)
	go func() {
		resp, err := httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters?watch=true")
		if err != nil {
			errc <- err
			return
		}
		if resp.StatusCode != 200 {
			errc <- errors.New("Invalid status code: " + resp.Status)
			return
		}
		log.Println("start watching...")
		for {
			decoder := json.NewDecoder(resp.Body)
			ev := new(Event)
			err = decoder.Decode(ev)
			if err != nil {
				errc <- err
			}
			log.Printf("etcd cluster event: %v %#v\n", ev.Type, ev.Object)
			events <- ev
		}
	}()

	return events, errc
}

func main() {
	c := &etcdClusterController{
		kclient:  mustCreateClient(masterHost),
		clusters: make(map[string]*Cluster),
	}
	log.Println("etcd cluster controller starts running...")
	c.Run()
}

func mustCreateClient(host string) *unversioned.Client {
	if len(host) == 0 {
		cfg, err := restclient.InClusterConfig()
		if err != nil {
			panic(err)
		}
		c, err := unversioned.NewInCluster()
		if err != nil {
			panic(err)
		}
		masterHost = cfg.Host
		return c
	}

	cfg := &restclient.Config{
		Host:  host,
		QPS:   100,
		Burst: 100,
	}
	c, err := unversioned.New(cfg)
	if err != nil {
		panic(err)
	}
	return c
}
<commit_msg>support https in off-cluster mode<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"

	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned"
)

var (
	masterHost  string
	tlsInsecure bool
	tlsConfig   restclient.TLSClientConfig
)

func init() {
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. 'http://127.0.0.1:8080'")
	flag.StringVar(&tlsConfig.CertFile, "cert-file", "", "Path to public TLS certificate file")
	flag.StringVar(&tlsConfig.KeyFile, "key-file", "", "Path to private TLS certificate file")
	flag.StringVar(&tlsConfig.CAFile, "ca-file", "", "Path to TLS CA file")
	flag.BoolVar(&tlsInsecure, "tls-insecure", false, "Don't verify API server's CA certificate - TESTING ONLY -")
	flag.Parse()
}

type EtcdCluster struct {
	Kind       string            `json:"kind"`
	ApiVersion string            `json:"apiVersion"`
	Metadata   map[string]string `json:"metadata"`
	Size       int               `json:"size"`
}

type Event struct {
	Type   string
	Object EtcdCluster
}

type etcdClusterController struct {
	kclient  *unversioned.Client
	clusters map[string]*Cluster
}

func (c *etcdClusterController) Run() {
	eventCh, errCh := monitorEtcdCluster(c.kclient.RESTClient.Client)
	for {
		select {
		case event := <-eventCh:
			clusterName := event.Object.Metadata["name"]
			switch event.Type {
			case "ADDED":
				c.clusters[clusterName] = newCluster(c.kclient, clusterName, event.Object.Size)
			case "DELETED":
				c.clusters[clusterName].Delete()
				delete(c.clusters, clusterName)
			}
		case err := <-errCh:
			panic(err)
		}
	}
}

func monitorEtcdCluster(httpClient *http.Client) (<-chan *Event, <-chan error) {
	events := make(chan *Event)
	errc := make(chan error, 1)
	go func() {
		resp, err := httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters?watch=true")
		if err != nil {
			errc <- err
			return
		}
		if resp.StatusCode != 200 {
			errc <- errors.New("Invalid status code: " + resp.Status)
			return
		}
		log.Println("start watching...")
		for {
			decoder := json.NewDecoder(resp.Body)
			ev := new(Event)
			err = decoder.Decode(ev)
			if err != nil {
				errc <- err
			}
			log.Printf("etcd cluster event: %v %#v\n", ev.Type, ev.Object)
			events <- ev
		}
	}()

	return events, errc
}

func main() {
	c := &etcdClusterController{
		kclient:  mustCreateClient(masterHost),
		clusters: make(map[string]*Cluster),
	}
	log.Println("etcd cluster controller starts running...")
	c.Run()
}

func mustCreateClient(host string) *unversioned.Client {
	if len(host) == 0 {
		cfg, err := restclient.InClusterConfig()
		if err != nil {
			panic(err)
		}
		c, err := unversioned.NewInCluster()
		if err != nil {
			panic(err)
		}
		masterHost = cfg.Host
		return c
	}

	hostUrl, err := url.Parse(host)
	if err != nil {
		panic(fmt.Sprintf("error parsing host url %s : %v", host, err))
	}
	cfg := &restclient.Config{
		Host:  host,
		QPS:   100,
		Burst: 100,
	}
	if hostUrl.Scheme == "https" {
		cfg.TLSClientConfig = tlsConfig
		cfg.Insecure = tlsInsecure
	}
	c, err := unversioned.New(cfg)
	if err != nil {
		panic(err)
	}
	return c
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"html/template"
	"log"
	"net/http"
	"os"
	"sort"
	"strconv"
	"time"

	_ "github.com/yansal/pollbc/Godeps/_workspace/src/github.com/lib/pq"
)

var paris *time.Location

func init() {
	var err error
	paris, err = time.LoadLocation("Europe/Paris")
	if err != nil {
		log.Fatal(err)
	}
}

type Place struct {
	ID             int
	City           string
	Department     string
	Arrondissement string
}

type Announce struct {
	ID    string
	Date  time.Time
	Price string
	Title string

	PlaceID int

	Fetched time.Time
}

type ByDate []Announce

func (d ByDate) Len() int           { return len(d) }
func (d ByDate) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d ByDate) Less(i, j int) bool { return d[i].Date.After(d[j].Date) }

var db *sql.DB

func init() {
	var err error
	db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	err = createTableAnnounces(db)
	if err != nil {
		log.Print(err)
	}

	err = createTablePlaces(db)
	if err != nil {
		log.Print(err)
	}

}

func poll() {
	for {
		doc, err := fetch()
		if err != nil {
			log.Print(err)
			time.Sleep(time.Minute)
			continue
		}
		nodes := queryAnnounces(doc)

		count := 0
		for _, n := range nodes {
			place, err := queryPlace(n)
			if err != nil {
				log.Print(err)
				continue
			}

			ok, err := hasPlace(db, place)
			if err != nil {
				log.Print(err)
			} else if !ok {
				err := insertPlace(db, place)
				if err != nil {
					log.Print(err)
				}
			}
			placeID, err := selectIDFromPlaces(db, place)
			if err != nil {
				log.Print(err)
			}

			id := queryID(n)
			if id == "" {
				continue
			}
			ok, err = hasAnnounce(db, id)
			if err != nil {
				log.Print(err)
			} else if !ok {
				count++
				ann := Announce{ID: id, Fetched: time.Now()}
				ann.Date = queryDate(n)
				ann.PlaceID = placeID
				ann.Price = queryPrice(n)
				ann.Title = queryTitle(n)
				err := insertAnnounce(db, ann)
				if err != nil {
					log.Print(err)
				}
			}
		}

		if count > 0 {
			// TODO: Notify by email?
			log.Printf("Number of new announces fetched:\t%d\n", count)
		}
		time.Sleep(5 * time.Second)
	}
}

func serveHTTP(w http.ResponseWriter, r *http.Request) {
	var ann []Announce
	var err error
	q := map[string][]string(r.URL.Query())
	placeIDs, ok := q["placeID"]
	if !ok {
		ann, err = selectAnnounces(db)
		if err != nil {
			log.Print(err)
		}
	} else {
		for _, placeID := range placeIDs {
			placeID, err := strconv.Atoi(placeID)
			if err != nil {
				log.Print(err)
			}
			newAnn, err := selectAnnouncesWherePlaceID(db, placeID)
			if err != nil {
				log.Print(err)
			}
			ann = append(ann, newAnn...)
		}
	}

	places := make(map[int]Place)
	for _, a := range ann {
		_, ok := places[a.PlaceID]
		if ok {
			continue
		}
		place, err := selectPlace(db, a.PlaceID)
		if err != nil {
			log.Print(err)
			continue
		}
		places[a.PlaceID] = place
	}
	sort.Sort(ByDate(ann))
	ann = ann[:35]

	data := struct {
		Announces []Announce
		Places    map[int]Place
	}{ann, places}
	t := template.Must(template.ParseFiles("template.html"))
	err = t.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	log.Printf("Listening on port %v", port)

	go poll()
	log.Fatal(http.ListenAndServe(":"+port, http.HandlerFunc(serveHTTP)))
}
<commit_msg>Fix bug introduced in #15<commit_after>package main

import (
	"database/sql"
	"html/template"
	"log"
	"net/http"
	"os"
	"sort"
	"strconv"
	"time"

	_ "github.com/yansal/pollbc/Godeps/_workspace/src/github.com/lib/pq"
)

var paris *time.Location

func init() {
	var err error
	paris, err = time.LoadLocation("Europe/Paris")
	if err != nil {
		log.Fatal(err)
	}
}

type Place struct {
	ID             int
	City           string
	Department     string
	Arrondissement string
}

type Announce struct {
	ID    string
	Date  time.Time
	Price string
	Title string

	PlaceID int

	Fetched time.Time
}

type ByDate []Announce

func (d ByDate) Len() int           { return len(d) }
func (d ByDate) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d ByDate) Less(i, j int) bool { return d[i].Date.After(d[j].Date) }

var db *sql.DB

func init() {
	var err error
	db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	err = createTableAnnounces(db)
	if err != nil {
		log.Print(err)
	}

	err = createTablePlaces(db)
	if err != nil {
		log.Print(err)
	}

}

func poll() {
	for {
		doc, err := fetch()
		if err != nil {
			log.Print(err)
			time.Sleep(time.Minute)
			continue
		}
		nodes := queryAnnounces(doc)

		count := 0
		for _, n := range nodes {
			place, err := queryPlace(n)
			if err != nil {
				log.Print(err)
				continue
			}

			ok, err := hasPlace(db, place)
			if err != nil {
				log.Print(err)
			} else if !ok {
				err := insertPlace(db, place)
				if err != nil {
					log.Print(err)
				}
			}
			placeID, err := selectIDFromPlaces(db, place)
			if err != nil {
				log.Print(err)
			}

			id := queryID(n)
			if id == "" {
				continue
			}
			ok, err = hasAnnounce(db, id)
			if err != nil {
				log.Print(err)
			} else if !ok {
				count++
				ann := Announce{ID: id, Fetched: time.Now()}
				ann.Date = queryDate(n)
				ann.PlaceID = placeID
				ann.Price = queryPrice(n)
				ann.Title = queryTitle(n)
				err := insertAnnounce(db, ann)
				if err != nil {
					log.Print(err)
				}
			}
		}

		if count > 0 {
			// TODO: Notify by email?
			log.Printf("Number of new announces fetched:\t%d\n", count)
		}
		time.Sleep(5 * time.Second)
	}
}

func serveHTTP(w http.ResponseWriter, r *http.Request) {
	var ann []Announce
	var err error
	q := map[string][]string(r.URL.Query())
	placeIDs, ok := q["placeID"]
	if !ok {
		ann, err = selectAnnounces(db)
		if err != nil {
			log.Print(err)
		}
	} else {
		for _, placeID := range placeIDs {
			placeID, err := strconv.Atoi(placeID)
			if err != nil {
				log.Print(err)
			}
			newAnn, err := selectAnnouncesWherePlaceID(db, placeID)
			if err != nil {
				log.Print(err)
			}
			ann = append(ann, newAnn...)
		}
	}

	places := make(map[int]Place)
	for _, a := range ann {
		_, ok := places[a.PlaceID]
		if ok {
			continue
		}
		place, err := selectPlace(db, a.PlaceID)
		if err != nil {
			log.Print(err)
			continue
		}
		places[a.PlaceID] = place
	}
	sort.Sort(ByDate(ann))
	if len(ann) > 35 {
		ann = ann[:35]
	}

	data := struct {
		Announces []Announce
		Places    map[int]Place
	}{ann, places}
	t := template.Must(template.ParseFiles("template.html"))
	err = t.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	log.Printf("Listening on port %v", port)

	go poll()
	log.Fatal(http.ListenAndServe(":"+port, http.HandlerFunc(serveHTTP)))
}
<|endoftext|>


<commit_before>// Copyright 2015 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/rcrowley/go-metrics"
	"github.com/square/go-sq-metrics"
	klog "github.com/square/keywhiz-fs/log"
	"golang.org/x/sys/unix"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	app = kingpin.New("keywhiz-fs", "A FUSE based file-system client for Keywhiz.")

	certFile       = app.Flag("cert", "PEM-encoded certificate file").Default("client.crt").String()
	keyFile        = app.Flag("key", "PEM-encoded private key file").Default("client.key").String()
	caFile         = app.Flag("ca", "PEM-encoded CA certificates file").Default("cacert.crt").String()
	asuser         = app.Flag("asuser", "Default user to own files").Default("keywhiz").String()
	asgroup        = app.Flag("group", "Default group to own files").Default("group").String()
	ping           = app.Flag("ping", "Enable startup ping to server").Default("false").Bool()
	debug          = app.Flag("debug", "Enable debugging output").Default("false").Bool()
	timeout        = app.Flag("timeout", "Timeout for communication with server").Default("20s").Duration()
	metricsURL     = app.Flag("metrics-url", "Collect metrics and POST them periodically to the given URL (via HTTP/JSON).").String()
	metricsPrefix  = app.Flag("metrics-prefix", "Override the default metrics prefix used for reporting metrics.").String()
	syslog         = app.Flag("syslog", "Send logs to syslog instead of stderr.").Default("false").Bool()
	serverURL      = app.Arg("url", "server url").Required().URL()
	mountpoint     = app.Arg("mountpoint", "mountpoint").Required().String()
	logger         *klog.Logger
)

func main() {
	app.Version(fmt.Sprintf("rev %s-%s on \"%s\"", buildRevision, buildTime, buildMachine))
	kingpin.MustParse(app.Parse(os.Args[1:]))

	logConfig := klog.Config{Debug: *debug, Mountpoint: *mountpoint, Syslog: *syslog}
	logger = klog.New("kwfs_main", logConfig)
	defer logger.Close()

	if *certFile == "" {
		logger.Debugf("Certificate file not specified, assuming certificate also in %s", *keyFile)
		certFile = keyFile
	}

	metricsHandle := setupMetrics(metricsURL, metricsPrefix, *mountpoint)

	lockMemory()

	freshThreshold := 1 * time.Hour
	backendDeadline := 5 * time.Second
	maxWait := *timeout + backendDeadline
	delayDeletion := 1 * time.Hour
	timeouts := Timeouts{freshThreshold, backendDeadline, maxWait, delayDeletion}

	client := NewClient(*certFile, *keyFile, *caFile, *serverURL, *timeout, logConfig)

	ownership := NewOwnership(*asuser, *asgroup)
	kwfs, root, err := NewKeywhizFs(&client, ownership, timeouts, metricsHandle, logConfig)
	if err != nil {
		log.Fatalf("KeywhizFs init fail: %v\n", err)
	}

	mountOptions := &fuse.MountOptions{
		AllowOther: true,
		Name:       kwfs.String(),
		Options:    []string{"default_permissions"},
	}

	// Empty Options struct avoids setting a global uid/gid override.
	conn := nodefs.NewFileSystemConnector(root, &nodefs.Options{})
	server, err := fuse.NewServer(conn.RawFS(), *mountpoint, mountOptions)
	if err != nil {
		log.Fatalf("Mount fail: %v\n", err)
	}

	// Catch SIGINT and exit cleanly.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for {
			sig := <-c
			logger.Warnf("Got signal %s, unmounting", sig)
			err := server.Unmount()
			if err != nil {
				logger.Warnf("Error while unmounting: %v", err)
			}
		}
	}()

	// Prime cache: we retrieve the initial secrets list right away, so that
	// we can make sure we're ready to show contents as soon as we get mounted.
	if *ping {
		ok := kwfs.Cache.pingBackend()
		if !ok {
			fmt.Fprintf(os.Stderr, "unable to talk to backend")
			os.Exit(1)
		}
	}

	server.Serve()
	logger.Infof("Exiting")
}

// Setup metrics
func setupMetrics(metricsURL *string, metricsPrefix *string, mountpoint string) *sqmetrics.SquareMetrics {
	if *metricsURL != "" {
		if !strings.HasPrefix(*metricsURL, "http://") && !strings.HasPrefix(*metricsURL, "https://") {
			log.Fatalf("--metrics-url should start with http:// or https://")
			os.Exit(1)
		}
		log.Printf("metrics enabled; reporting metrics via POST to %s", *metricsURL)
	}

	var prefix string
	if *metricsPrefix != "" {
		prefix = *metricsPrefix
	} else {
		// By default, prefix metrics with escaped mount path. Replace slashes with - for easier aggregation
		prefix = fmt.Sprintf("keywhizfs.%s", strings.Replace(strings.Replace(mountpoint, "-", "--", -1), "/", "-", -1))
	}

	return sqmetrics.NewMetrics(*metricsURL, prefix, metrics.DefaultRegistry)
}

// Locks memory, preventing memory from being written to disk as swap
func lockMemory() {
	err := unix.Mlockall(unix.MCL_FUTURE | unix.MCL_CURRENT)
	switch err {
	case nil:
	case unix.ENOSYS:
		logger.Warnf("mlockall() not implemented on this system")
	case unix.ENOMEM:
		logger.Warnf("mlockall() failed with ENOMEM")
	default:
		log.Fatalf("Could not perform mlockall and prevent swapping memory: %v", err)
	}
}

// Helper function to panic on error
func panicOnError(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Log when panicOnError() is called.<commit_after>// Copyright 2015 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/rcrowley/go-metrics"
	"github.com/square/go-sq-metrics"
	klog "github.com/square/keywhiz-fs/log"
	"golang.org/x/sys/unix"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	app = kingpin.New("keywhiz-fs", "A FUSE based file-system client for Keywhiz.")

	certFile       = app.Flag("cert", "PEM-encoded certificate file").Default("client.crt").String()
	keyFile        = app.Flag("key", "PEM-encoded private key file").Default("client.key").String()
	caFile         = app.Flag("ca", "PEM-encoded CA certificates file").Default("cacert.crt").String()
	asuser         = app.Flag("asuser", "Default user to own files").Default("keywhiz").String()
	asgroup        = app.Flag("group", "Default group to own files").Default("group").String()
	ping           = app.Flag("ping", "Enable startup ping to server").Default("false").Bool()
	debug          = app.Flag("debug", "Enable debugging output").Default("false").Bool()
	timeout        = app.Flag("timeout", "Timeout for communication with server").Default("20s").Duration()
	metricsURL     = app.Flag("metrics-url", "Collect metrics and POST them periodically to the given URL (via HTTP/JSON).").String()
	metricsPrefix  = app.Flag("metrics-prefix", "Override the default metrics prefix used for reporting metrics.").String()
	syslog         = app.Flag("syslog", "Send logs to syslog instead of stderr.").Default("false").Bool()
	serverURL      = app.Arg("url", "server url").Required().URL()
	mountpoint     = app.Arg("mountpoint", "mountpoint").Required().String()
	logger         *klog.Logger
)

func main() {
	app.Version(fmt.Sprintf("rev %s-%s on \"%s\"", buildRevision, buildTime, buildMachine))
	kingpin.MustParse(app.Parse(os.Args[1:]))

	logConfig := klog.Config{Debug: *debug, Mountpoint: *mountpoint, Syslog: *syslog}
	logger = klog.New("kwfs_main", logConfig)
	defer logger.Close()

	if *certFile == "" {
		logger.Debugf("Certificate file not specified, assuming certificate also in %s", *keyFile)
		certFile = keyFile
	}

	metricsHandle := setupMetrics(metricsURL, metricsPrefix, *mountpoint)

	lockMemory()

	freshThreshold := 1 * time.Hour
	backendDeadline := 5 * time.Second
	maxWait := *timeout + backendDeadline
	delayDeletion := 1 * time.Hour
	timeouts := Timeouts{freshThreshold, backendDeadline, maxWait, delayDeletion}

	client := NewClient(*certFile, *keyFile, *caFile, *serverURL, *timeout, logConfig)

	ownership := NewOwnership(*asuser, *asgroup)
	kwfs, root, err := NewKeywhizFs(&client, ownership, timeouts, metricsHandle, logConfig)
	if err != nil {
		log.Fatalf("KeywhizFs init fail: %v\n", err)
	}

	mountOptions := &fuse.MountOptions{
		AllowOther: true,
		Name:       kwfs.String(),
		Options:    []string{"default_permissions"},
	}

	// Empty Options struct avoids setting a global uid/gid override.
	conn := nodefs.NewFileSystemConnector(root, &nodefs.Options{})
	server, err := fuse.NewServer(conn.RawFS(), *mountpoint, mountOptions)
	if err != nil {
		log.Fatalf("Mount fail: %v\n", err)
	}

	// Catch SIGINT and exit cleanly.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for {
			sig := <-c
			logger.Warnf("Got signal %s, unmounting", sig)
			err := server.Unmount()
			if err != nil {
				logger.Warnf("Error while unmounting: %v", err)
			}
		}
	}()

	// Prime cache: we retrieve the initial secrets list right away, so that
	// we can make sure we're ready to show contents as soon as we get mounted.
	if *ping {
		ok := kwfs.Cache.pingBackend()
		if !ok {
			fmt.Fprintf(os.Stderr, "unable to talk to backend")
			os.Exit(1)
		}
	}

	server.Serve()
	logger.Infof("Exiting")
}

// Setup metrics
func setupMetrics(metricsURL *string, metricsPrefix *string, mountpoint string) *sqmetrics.SquareMetrics {
	if *metricsURL != "" {
		if !strings.HasPrefix(*metricsURL, "http://") && !strings.HasPrefix(*metricsURL, "https://") {
			log.Fatalf("--metrics-url should start with http:// or https://")
			os.Exit(1)
		}
		log.Printf("metrics enabled; reporting metrics via POST to %s", *metricsURL)
	}

	var prefix string
	if *metricsPrefix != "" {
		prefix = *metricsPrefix
	} else {
		// By default, prefix metrics with escaped mount path. Replace slashes with - for easier aggregation
		prefix = fmt.Sprintf("keywhizfs.%s", strings.Replace(strings.Replace(mountpoint, "-", "--", -1), "/", "-", -1))
	}

	return sqmetrics.NewMetrics(*metricsURL, prefix, metrics.DefaultRegistry)
}

// Locks memory, preventing memory from being written to disk as swap
func lockMemory() {
	err := unix.Mlockall(unix.MCL_FUTURE | unix.MCL_CURRENT)
	switch err {
	case nil:
	case unix.ENOSYS:
		logger.Warnf("mlockall() not implemented on this system")
	case unix.ENOMEM:
		logger.Warnf("mlockall() failed with ENOMEM")
	default:
		log.Fatalf("Could not perform mlockall and prevent swapping memory: %v", err)
	}
}

// Helper function to panic on error
func panicOnError(err error) {
	if err != nil {
		logger.Errorf("panic: %v", err)
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"strings"
	"time"

	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
)

const driverName = "driver-ble"

type waypointPayload struct {
	Sequence    uint8
	AddressType uint8
	Rssi        int8
	Valid       uint8
}

type adPacket struct {
	Device   string `json:"device"`
	Waypoint string `json:"waypoint"`
	Rssi     int8   `json:"rssi"`
	IsSphere bool   `json:"isSphere"`
}

type ninjaPacket struct {
	Device   string `json:"device"`
	Waypoint string `json:"waypoint"`
	Rssi     int8   `json:"rssi"`
	IsSphere bool   `json:"isSphere"`
	name 	 string `json:"name,omitempty"`
}

// configure the agent logger
var log = logger.GetLogger("driver-go-ble")

//var mesh *udpMesh

func sendRssi(device string, name string, waypoint string, rssi int8, isSphere bool, conn *ninja.Connection) {
	device = strings.ToUpper(device)

	log.Debugf(">> Device:%s Waypoint:%s Rssi: %d", device, waypoint, rssi)

	ninjaPacket := ninjaPacket{
		Device:   device,
		Waypoint: waypoint,
		Rssi:     rssi,
		IsSphere: isSphere,
		name: name,
	}

	//spew.Dump(packet)
	conn.SendNotification("$device/"+device+"/TEMPPATH/rssi", ninjaPacket)

}

func publishMessage(conn *ninja.Connection, topic string, packet interface{}) {
	p, err := json.Marshal(packet)
	if err == nil {
		conn.GetMqttClient().Publish(mqtt.QoS(0), topic, p)
	} else {
		log.Fatalf("marshalling error for %v", packet)
	}
}

func main() {
	os.Exit(realMain())
}

func realMain() int {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.ble")

	if err != nil {
		log.FatalErrorf(err, "Could not connect to MQTT Broker")
	}

	/*if mesh, err = newUdpMesh("239.255.12.34:12345", func(packet *adPacket) {

		spew.Dump("Got mesh packet", packet)

	}); err != nil {
		log.FatalErrorf(err, "Could not connect to UDP mesh")
	}*/

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalErrorf(err, "Could not setup status job")
	}

	statusJob.Start()

	out, err := exec.Command("hciconfig").Output()
	if err != nil {
		log.Errorf(fmt.Sprintf("Error: %s", err))
	}
	re := regexp.MustCompile("([0-9A-F]{2}\\:{0,1}){6}")
	mac := strings.Replace(re.FindString(string(out)), ":", "", -1)
	log.Infof("The local mac is %s\n", mac)

	client := &gatt.Client{
		StateChange: func(newState string) {
			log.Infof("Client state change: %s", newState)
		},
	}

	/*
	  Waypoint notification characteristic {
	    "startHandle": 45,
	    "properties": 16, (useNotify = true, useIndicate = false)
	    "valueHandle": 46,
	    "uuid": "fff4",
	    "endHandle": 48,
	  }
	*/

	activeWaypoints := make(map[string]bool)

	go func() {
		for {
			time.Sleep(time.Second)
			waypoints := 0
			for id, active := range activeWaypoints {
				log.Debugf("Waypoint %s is active? %t", id, active)
				if active {
					waypoints++
				}
			}
			log.Debugf("%d waypoint(s) active", waypoints)

			publishMessage(conn, "$location/waypoints", waypoints)
		}
	}()

	client.Rssi = func(address string, name string, rssi int8) {
		//log.Printf("Rssi update address:%s rssi:%d", address, rssi)
		sendRssi(strings.Replace(address, ":", "", -1), name, mac, rssi, true, conn)
		//spew.Dump(device);
	}

	client.Advertisement = func(device *gatt.DiscoveredDevice) {
		log.Debugf("Discovered address:%s rssi:%d", device.Address, device.Rssi)

		if device.Advertisement.LocalName != "NinjaSphereWaypoint" {
			return
		}

		if activeWaypoints[device.Address] {
			return
		}

		if device.Connected == nil {
			device.Connected = func() {
				log.Infof("Connected to waypoint: %s", device.Address)
				//spew.Dump(device.Advertisement)

				// XXX: Yes, magic numbers.... this enables the notification from our Waypoints
				client.Notify(device.Address, true, 45, 48, true, false)
			}

			device.Disconnected = func() {
				log.Infof("Disconnected from waypoint: %s", device.Address)

				activeWaypoints[device.Address] = false
			}

			device.Notification = func(notification *gatt.Notification) {
				//log.Printf("Got the notification!")

				//XXX: Add the ieee into the payload somehow??
				var payload waypointPayload
				err := binary.Read(bytes.NewReader(notification.Data), binary.LittleEndian, &payload)
				if err != nil {
					log.Errorf("Failed to read waypoint payload : %s", err)
				}

				//	ieee := net.HardwareAddr(reverse(notification.Data[4:]))

				//spew.Dump("ieee:", payload)

				packet := &adPacket{
					Device:   fmt.Sprintf("%x", reverse(notification.Data[4:])),
					Waypoint: strings.Replace(device.Address, ":", "", -1),
					Rssi:     payload.Rssi,
					IsSphere: false,
				}

				sendRssi(packet.Device, "", packet.Waypoint, packet.Rssi, packet.IsSphere, conn)
				//mesh.send(packet)
			}
		}

		err := client.Connect(device.Address, device.PublicAddress)
		if err != nil {
			log.Errorf("Connect error:%s", err)
			return
		}

		activeWaypoints[device.Address] = true

	}

	err = client.Start()

	if err != nil {
		log.FatalError(err, "Failed to start client")
	}

	err = client.StartScanning(true)
	if err != nil {
		log.FatalError(err, "Failed to start scanning")
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	// Block until a signal is received.
	s := <-c
	log.Infof("Got signal:", s)

	return 0
}

// reverse returns a reversed copy of u.
func reverse(u []byte) []byte {
	l := len(u)
	b := make([]byte, l)
	for i := 0; i < l/2+1; i++ {
		b[i], b[l-i-1] = u[l-i-1], u[i]
	}
	return b
}
<commit_msg>Change logging of connect disconnect events to debug level.<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"strings"
	"time"

	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
)

const driverName = "driver-ble"

type waypointPayload struct {
	Sequence    uint8
	AddressType uint8
	Rssi        int8
	Valid       uint8
}

type adPacket struct {
	Device   string `json:"device"`
	Waypoint string `json:"waypoint"`
	Rssi     int8   `json:"rssi"`
	IsSphere bool   `json:"isSphere"`
}

type ninjaPacket struct {
	Device   string `json:"device"`
	Waypoint string `json:"waypoint"`
	Rssi     int8   `json:"rssi"`
	IsSphere bool   `json:"isSphere"`
	name 	 string `json:"name,omitempty"`
}

// configure the agent logger
var log = logger.GetLogger("driver-go-ble")

//var mesh *udpMesh

func sendRssi(device string, name string, waypoint string, rssi int8, isSphere bool, conn *ninja.Connection) {
	device = strings.ToUpper(device)

	log.Debugf(">> Device:%s Waypoint:%s Rssi: %d", device, waypoint, rssi)

	ninjaPacket := ninjaPacket{
		Device:   device,
		Waypoint: waypoint,
		Rssi:     rssi,
		IsSphere: isSphere,
		name: name,
	}

	//spew.Dump(packet)
	conn.SendNotification("$device/"+device+"/TEMPPATH/rssi", ninjaPacket)

}

func publishMessage(conn *ninja.Connection, topic string, packet interface{}) {
	p, err := json.Marshal(packet)
	if err == nil {
		conn.GetMqttClient().Publish(mqtt.QoS(0), topic, p)
	} else {
		log.Fatalf("marshalling error for %v", packet)
	}
}

func main() {
	os.Exit(realMain())
}

func realMain() int {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.ble")

	if err != nil {
		log.FatalErrorf(err, "Could not connect to MQTT Broker")
	}

	/*if mesh, err = newUdpMesh("239.255.12.34:12345", func(packet *adPacket) {

		spew.Dump("Got mesh packet", packet)

	}); err != nil {
		log.FatalErrorf(err, "Could not connect to UDP mesh")
	}*/

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalErrorf(err, "Could not setup status job")
	}

	statusJob.Start()

	out, err := exec.Command("hciconfig").Output()
	if err != nil {
		log.Errorf(fmt.Sprintf("Error: %s", err))
	}
	re := regexp.MustCompile("([0-9A-F]{2}\\:{0,1}){6}")
	mac := strings.Replace(re.FindString(string(out)), ":", "", -1)
	log.Infof("The local mac is %s\n", mac)

	client := &gatt.Client{
		StateChange: func(newState string) {
			log.Infof("Client state change: %s", newState)
		},
	}

	/*
	  Waypoint notification characteristic {
	    "startHandle": 45,
	    "properties": 16, (useNotify = true, useIndicate = false)
	    "valueHandle": 46,
	    "uuid": "fff4",
	    "endHandle": 48,
	  }
	*/

	activeWaypoints := make(map[string]bool)

	go func() {
		for {
			time.Sleep(time.Second)
			waypoints := 0
			for id, active := range activeWaypoints {
				log.Debugf("Waypoint %s is active? %t", id, active)
				if active {
					waypoints++
				}
			}
			log.Debugf("%d waypoint(s) active", waypoints)

			publishMessage(conn, "$location/waypoints", waypoints)
		}
	}()

	client.Rssi = func(address string, name string, rssi int8) {
		//log.Printf("Rssi update address:%s rssi:%d", address, rssi)
		sendRssi(strings.Replace(address, ":", "", -1), name, mac, rssi, true, conn)
		//spew.Dump(device);
	}

	client.Advertisement = func(device *gatt.DiscoveredDevice) {
		log.Debugf("Discovered address:%s rssi:%d", device.Address, device.Rssi)

		if device.Advertisement.LocalName != "NinjaSphereWaypoint" {
			return
		}

		if activeWaypoints[device.Address] {
			return
		}

		if device.Connected == nil {
			device.Connected = func() {
				log.Debugf("Connected to waypoint: %s", device.Address)
				//spew.Dump(device.Advertisement)

				// XXX: Yes, magic numbers.... this enables the notification from our Waypoints
				client.Notify(device.Address, true, 45, 48, true, false)
			}

			device.Disconnected = func() {
				log.Debugf("Disconnected from waypoint: %s", device.Address)

				activeWaypoints[device.Address] = false
			}

			device.Notification = func(notification *gatt.Notification) {
				//log.Printf("Got the notification!")

				//XXX: Add the ieee into the payload somehow??
				var payload waypointPayload
				err := binary.Read(bytes.NewReader(notification.Data), binary.LittleEndian, &payload)
				if err != nil {
					log.Errorf("Failed to read waypoint payload : %s", err)
				}

				//	ieee := net.HardwareAddr(reverse(notification.Data[4:]))

				//spew.Dump("ieee:", payload)

				packet := &adPacket{
					Device:   fmt.Sprintf("%x", reverse(notification.Data[4:])),
					Waypoint: strings.Replace(device.Address, ":", "", -1),
					Rssi:     payload.Rssi,
					IsSphere: false,
				}

				sendRssi(packet.Device, "", packet.Waypoint, packet.Rssi, packet.IsSphere, conn)
				//mesh.send(packet)
			}
		}

		err := client.Connect(device.Address, device.PublicAddress)
		if err != nil {
			log.Errorf("Connect error:%s", err)
			return
		}

		activeWaypoints[device.Address] = true

	}

	err = client.Start()

	if err != nil {
		log.FatalError(err, "Failed to start client")
	}

	err = client.StartScanning(true)
	if err != nil {
		log.FatalError(err, "Failed to start scanning")
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	// Block until a signal is received.
	s := <-c
	log.Infof("Got signal:", s)

	return 0
}

// reverse returns a reversed copy of u.
func reverse(u []byte) []byte {
	l := len(u)
	b := make([]byte, l)
	for i := 0; i < l/2+1; i++ {
		b[i], b[l-i-1] = u[l-i-1], u[i]
	}
	return b
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
	//"database/sql"

	"github.com/NoahShen/go-simsimi"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/xuyu/goredis"
)

var bot *linebot.Client
var session *simsimi.SimSimiSession
var Redis *goredis.Redis

const (
	ADD_EXPENSE = "/add-expense"
	ADD_INCOME  = "/add-income"
	PLAN        = "/plan"
)

type DataWallet struct {
	Data Wallet
}

type Wallet struct {
	UserInfo     Info
	GroupInfo    Info
	Money        int
	Income       map[int]map[int][]TransactionInfo
	Expense      map[int]map[int][]TransactionInfo
	Plan_Income  map[int]map[int][]TransactionInfo
	Plan_Expense map[int]map[int][]TransactionInfo
	Last_Action  LastAction
}

type LastAction struct {
	Status      bool
	Keyword     string
	Description string
	Price       int
	Category    string
}

type Info struct {
	ID string
}

type TransactionInfo struct {
	Created_by   string
	Price        int
	Created_date time.Time
	Planned_date time.Time
}

func main() {
	var err error

	connectRedis()
	session, _ = simsimi.CreateSimSimiSession("Wallte")
	bot, err = linebot.New(os.Getenv("CHANNEL_SECRET"), os.Getenv("CHANNEL_TOKEN"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func connectRedis() {
	var err error
	Redis, err = goredis.DialURL("tcp://redistogo:64bde566709b097ee1b3f512d6fab925@grouper.redistogo.com:11207/0?timeout=10s")
	if err != nil {
		log.Println(err.Error())
		return
	}
}

func connectDB() (*sqlx.DB, error) {
	db, err := sqlx.Open("mysql", os.Getenv("DB_CONNECT"))
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	return db, nil
}

func GetRedis(key string) string {
	data, err := Redis.Get(key)

	if err != nil {
		return ""
	}

	return string(data)
}

func SetRedis(key string, value string) {

	err := Redis.Set(key, value, 0, 0, false, false)
	if err != nil {
		log.Printf("%#v\n", err)
		return
	}

}

func executeQuery(query string) *sqlx.Rows {
	db, err := connectDB()
	if err != nil {
		log.Println(err.Error())
		return nil
	}
	defer db.Close()
	rows, err := db.Queryx(query)
	if err != nil {
		log.Println(err.Error())
		return nil
	}
	return rows
}

func executeInsert(json string, userID string, roomID string, groupID string) {
	db, err := connectDB()

	if err != nil {
		log.Println(err.Error())
		return
	}
	defer db.Close()
	tx := db.MustBegin()
	tx.MustExec("INSERT INTO wallte_data VALUES($1,$2,$3,$4)", userID, roomID, groupID, json)
	tx.Commit()
}

func executeUpdate(json string, userID string, roomID string, groupID string) {
	db, err := connectDB()
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer db.Close()
	tx := db.MustBegin()
	tx.MustExec("update wallte_data set JSON=$1 where user_id=$2 and room_id=$3 and group_id=$4", json, userID, roomID, groupID)
	tx.Commit()
}

func Marshal(data interface{}) (string, error) {

	res, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func updateData(data DataWallet, isUpdate bool, userID string, roomID string, groupID string) {
	res, err := Marshal(data)
	if err != nil || res == "" {
		return
	}

	redisKey := userID
	if roomID != "" {
		redisKey = roomID
	}

	if groupID != "" {
		redisKey = groupID
	}

	SetRedis(redisKey, res)
	if isUpdate {
		executeUpdate(res, userID, roomID, groupID)
		return
	}

	executeInsert(res, userID, roomID, groupID)
}

func getUserData(ID string) (*DataWallet, bool) {
	var data *DataWallet
	res := GetRedis(ID)
	if res != "" && res != "nil" {
		err := json.Unmarshal([]byte(res), &data)
		if err == nil {
			return data, true
		}
	}

	query := fmt.Sprintf("SELECT JSON FROM wallte_data WHERE user_id=%s OR group_id=%s OR room_id=%s LIMIT 1", ID, ID, ID)
	rows := executeQuery(query)
	defer rows.Close()
	if rows == nil {
		return nil, false
	}

	if rows.Next() {
		var jsonString string
		err := rows.Scan(&jsonString)
		if err != nil {
			return nil, false
		}

		err = json.Unmarshal([]byte(jsonString), &data)
		if err == nil {
			return data, true
		}
	}

	return nil, false
}

func FetchDataSource(event *linebot.Event) (string, string, string, *DataWallet, bool) {
	userID := ""
	roomID := ""
	groupID := ""

	var data *DataWallet
	var exist bool

	source := event.Source
	switch source.Type {
	case linebot.EventSourceTypeUser:
		userID = source.UserID
		data, exist = getUserData(userID)
	case linebot.EventSourceTypeGroup:
		roomID = source.RoomID
		data, exist = getUserData(roomID)
	case linebot.EventSourceTypeRoom:
		groupID = source.GroupID
		data, exist = getUserData(groupID)
	}

	return userID, roomID, groupID, data, exist
}

func handleTextMessage(event *linebot.Event, message *linebot.TextMessage) {

	userID, roomID, groupID, data, exist := FetchDataSource(event)

	fmt.Println(data, exist, userID, groupID, roomID)

	if message.Text == ADD_EXPENSE {

		if _, err := bot.ReplyMessage(
			event.ReplyToken,
			linebot.NewTextMessage(message.ID+":"+message.Text+" OK!"),
		).Do(); err != nil {
			return
		}

	} else if message.Text == ADD_INCOME {

	} else if message.Text == PLAN {

	}
	/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" OK!")).Do(); err != nil {
		log.Print(err)
	}*/
	/*imageURL := "https://drive.google.com/file/d/0Bx6cTEFypiiNaHVTcXV5VkFpbFE/view?usp=sharing"
	template := linebot.NewButtonsTemplate(
		imageURL, "My button sample"+message.Text, "Hello, my button",
		linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
		linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
		linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
		linebot.NewMessageTemplateAction("Say message", "Rice=米"),
	)
	if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewTemplateMessage("Buttons alt text", template),
	).Do(); err != nil {
		return
	}

	responseText, _ := session.Talk(message.Text)
	if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(responseText)).Do(); err != nil {
		log.Print(err)
	}*/
}

func handleSticker(event *linebot.Event, message *linebot.StickerMessage) {
	if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewStickerMessage(message.PackageID, message.StickerID),
	).Do(); err != nil {
		log.Println(err)
	}
}

func handleMessage(event *linebot.Event) {
	switch message := event.Message.(type) {
	case *linebot.TextMessage:
		handleTextMessage(event, message)
	case *linebot.StickerMessage:
		handleSticker(event, message)
	}
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {

			handleMessage(event)

		} else if event.Type == linebot.EventTypePostback {
			/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("iniPostback")).Do(); err != nil {
				log.Print(err)
			}*/

			//imageURL := "https://github.com/AdityaMili95/Wallte/blob/master/README/qI5Ujdy9n1.png"
			/*template := linebot.NewCarouselTemplate(
				linebot.NewCarouselColumn(
					imageURL, "hoge", "fuga",
					linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
				),
				linebot.NewCarouselColumn(
					imageURL, "hoge", "fuga",
					linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Carousel alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

			/*profile, err := bot.GetProfile(event.Source.UserID).Do()
			if(err!=nil){
				log.Print(err)
				return;
			}
			template := linebot.NewImageCarouselTemplate(
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewURITemplateAction("Go to LINE", "https://line.me"),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", "Hello"+profile.UserID),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewDatetimePickerTemplateAction("datetime", "DATETIME", "datetime", "", "", ""),
				),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Image carousel alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

			/*template := linebot.NewButtonsTemplate(
				"", "", "Select date / time !",
				linebot.NewDatetimePickerTemplateAction("date", "DATE", "date", "", "", ""),
				linebot.NewDatetimePickerTemplateAction("time", "TIME", "time", "", "", ""),
				linebot.NewDatetimePickerTemplateAction("datetime", "DATETIME", "datetime", "", "", ""),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Datetime pickers alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

		}

	}
}
<commit_msg>start functional<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
	//"database/sql"

	"github.com/NoahShen/go-simsimi"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/xuyu/goredis"
)

var bot *linebot.Client
var session *simsimi.SimSimiSession
var Redis *goredis.Redis

const (
	ADD_EXPENSE = "add-expense"
	ADD_INCOME  = "add-income"
	PLAN        = "plan"
	USER        = 1
	ROOM        = 2
	GROUP       = 3
)

type DataWallet struct {
	Data Wallet
}

type Wallet struct {
	UserInfo     Info
	GroupInfo    Info
	Money        int
	Income       map[int]map[int][]TransactionInfo
	Expense      map[int]map[int][]TransactionInfo
	Plan_Income  map[int]map[int][]TransactionInfo
	Plan_Expense map[int]map[int][]TransactionInfo
	Last_Action  LastAction
}

type LastAction struct {
	Status      bool
	Keyword     string
	Description string
	Price       int
	Category    string
}

type Info struct {
	ID string
}

type TransactionInfo struct {
	Created_by   string
	Price        int
	Created_date time.Time
	Planned_date time.Time
}

func main() {
	var err error

	connectRedis()
	session, _ = simsimi.CreateSimSimiSession("Wallte")
	bot, err = linebot.New(os.Getenv("CHANNEL_SECRET"), os.Getenv("CHANNEL_TOKEN"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func connectRedis() {
	var err error
	Redis, err = goredis.DialURL("tcp://redistogo:64bde566709b097ee1b3f512d6fab925@grouper.redistogo.com:11207/0?timeout=10s")
	if err != nil {
		log.Println(err.Error())
		return
	}
}

func connectDB() (*sqlx.DB, error) {
	db, err := sqlx.Open("mysql", os.Getenv("DB_CONNECT"))
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	return db, nil
}

func GetRedis(key string) string {
	data, err := Redis.Get(key)

	if err != nil {
		log.Println(err)
		return ""
	}

	return string(data)
}

func SetRedis(key string, value string) {

	err := Redis.Set(key, value, 0, 0, false, false)
	if err != nil {
		log.Printf("%#v\n", err)
		return
	}

}

func executeQuery(query string) *sqlx.Rows {
	db, err := connectDB()
	if err != nil {
		log.Println(err.Error())
		return nil
	}
	defer db.Close()
	rows, err := db.Queryx(query)
	if err != nil {
		log.Println(err.Error())
		return nil
	}
	return rows
}

func executeInsert(json string, userID string, roomID string, groupID string) {
	db, err := connectDB()

	if err != nil {
		log.Println(err.Error())
		return
	}
	defer db.Close()
	tx := db.MustBegin()
	tx.MustExec("INSERT INTO wallte_data VALUES($1,$2,$3,$4)", userID, roomID, groupID, json)
	tx.Commit()
}

func executeUpdate(json string, userID string, roomID string, groupID string) {
	db, err := connectDB()
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer db.Close()
	tx := db.MustBegin()
	tx.MustExec("update wallte_data set JSON=$1 where user_id=$2 and room_id=$3 and group_id=$4", json, userID, roomID, groupID)
	tx.Commit()
}

func Marshal(data interface{}) (string, error) {

	res, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func updateData(data DataWallet, isUpdate bool, userID string, roomID string, groupID string) {
	res, err := Marshal(data)
	if err != nil || res == "" {
		return
	}

	redisKey := userID
	if roomID != "" {
		redisKey = roomID
	}

	if groupID != "" {
		redisKey = groupID
	}

	SetRedis(redisKey, res)
	if isUpdate {
		executeUpdate(res, userID, roomID, groupID)
		return
	}

	executeInsert(res, userID, roomID, groupID)
}

func prepareUpdateData(data DataWallet, isUpdate bool, userID string, roomID string, groupID string, msgType int) {
	if msgType == USER {
		updateData(data, isUpdate, userID, "", "")
	} else if msgType == ROOM {
		updateData(data, isUpdate, "", roomID, "")
	} else if msgType == GROUP {
		updateData(data, isUpdate, "", "", groupID)
	}
}

func getUserData(ID string) (*DataWallet, bool) {
	var data *DataWallet
	res := GetRedis(ID)
	if res != "" && res != "nil" {
		err := json.Unmarshal([]byte(res), &data)
		if err == nil {
			return data, true
		}
	}

	query := fmt.Sprintf("SELECT JSON FROM wallte_data WHERE user_id=%s OR group_id=%s OR room_id=%s LIMIT 1", ID, ID, ID)
	rows := executeQuery(query)
	defer rows.Close()
	if rows == nil {
		return nil, false
	}

	if rows.Next() {
		var jsonString string
		err := rows.Scan(&jsonString)
		if err != nil {
			return nil, false
		}

		err = json.Unmarshal([]byte(jsonString), &data)
		if err == nil {
			return data, true
		}
	}

	return nil, false
}

func FetchDataSource(event *linebot.Event) (string, string, string, *DataWallet, bool, int) {
	userID := ""
	roomID := ""
	groupID := ""

	var data *DataWallet
	var exist bool
	var msgType int

	source := event.Source
	switch source.Type {
	case linebot.EventSourceTypeUser:
		userID = source.UserID
		data, exist = getUserData(userID)
		msgType = USER
	case linebot.EventSourceTypeGroup:
		roomID = source.RoomID
		userID = source.UserID
		data, exist = getUserData(roomID)
		msgType = ROOM
	case linebot.EventSourceTypeRoom:
		groupID = source.GroupID
		userID = source.UserID
		data, exist = getUserData(groupID)
		msgType = GROUP
	}

	return userID, roomID, groupID, data, exist, msgType
}

func handleAddExpense(splitted []string, event *linebot.Event, exist bool, userID string, roomID string, groupID string, data *DataWallet, msgType int) {
	imageURL := "https://github.com/AdityaMili95/Wallte/raw/master/README/qI5Ujdy9n1.png"
	/*if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewTextMessage(message.ID+":"+message.Text+" OK!"),
	).Do(); err != nil {
		return
	}*/

	template := linebot.NewImageCarouselTemplate(
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewPostbackTemplateAction("Food", "/add-expense/food", ""),
		),
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewPostbackTemplateAction("Transportation", "/add-expense/transport", ""),
		),
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewPostbackTemplateAction("Social", "/add-expense/social", ""),
		),
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewPostbackTemplateAction("Life", "/add-expense/life", ""),
		),
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewPostbackTemplateAction("Other", "/add-expense/other", ""),
		),
		linebot.NewImageCarouselColumn(
			imageURL,
			linebot.NewURITemplateAction("Shop Now", "https://tokopedia.com/elefashionshop"),
		),
	)
	if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewTemplateMessage("Select Expense Category!!", template),
	).Do(); err != nil {
		log.Print(err)
	}
}

func handleTextMessage(event *linebot.Event, message *linebot.TextMessage) {

	userID, roomID, groupID, data, exist, msgType := FetchDataSource(event)
	//fmt.Println(data, exist, userID, groupID, roomID)

	mainType := strings.Split(message.Text, "/")
	lenSplitted := len(mainType)

	msgCategory := ""
	if lenSplitted > 1 {
		msgCategory = mainType[1]
	}

	if msgCategory == ADD_EXPENSE {
		handleAddExpense(mainType, event, exist, userID, roomID, groupID, data, msgType)
	} else if msgCategory == ADD_INCOME {

	} else if msgCategory == PLAN {

	}
	/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" OK!")).Do(); err != nil {
		log.Print(err)
	}*/
	/*imageURL := "https://drive.google.com/file/d/0Bx6cTEFypiiNaHVTcXV5VkFpbFE/view?usp=sharing"
	template := linebot.NewButtonsTemplate(
		imageURL, "My button sample"+message.Text, "Hello, my button",
		linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
		linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
		linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
		linebot.NewMessageTemplateAction("Say message", "Rice=米"),
	)
	if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewTemplateMessage("Buttons alt text", template),
	).Do(); err != nil {
		return
	}

	responseText, _ := session.Talk(message.Text)
	if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(responseText)).Do(); err != nil {
		log.Print(err)
	}*/
}

func handleSticker(event *linebot.Event, message *linebot.StickerMessage) {
	if _, err := bot.ReplyMessage(
		event.ReplyToken,
		linebot.NewStickerMessage(message.PackageID, message.StickerID),
	).Do(); err != nil {
		log.Println(err)
	}
}

func handleMessage(event *linebot.Event) {
	switch message := event.Message.(type) {
	case *linebot.TextMessage:
		handleTextMessage(event, message)
	case *linebot.StickerMessage:
		handleSticker(event, message)
	}
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {

			handleMessage(event)

		} else if event.Type == linebot.EventTypePostback {
			/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("iniPostback")).Do(); err != nil {
				log.Print(err)
			}*/

			//imageURL := "https://github.com/AdityaMili95/Wallte/blob/master/README/qI5Ujdy9n1.png"
			/*template := linebot.NewCarouselTemplate(
				linebot.NewCarouselColumn(
					imageURL, "hoge", "fuga",
					linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
				),
				linebot.NewCarouselColumn(
					imageURL, "hoge", "fuga",
					linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Carousel alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

			/*profile, err := bot.GetProfile(event.Source.UserID).Do()
			if(err!=nil){
				log.Print(err)
				return;
			}
			template := linebot.NewImageCarouselTemplate(
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewURITemplateAction("Go to LINE", "https://line.me"),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", "Hello"+profile.UserID),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				),
				linebot.NewImageCarouselColumn(
					imageURL,
					linebot.NewDatetimePickerTemplateAction("datetime", "DATETIME", "datetime", "", "", ""),
				),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Image carousel alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

			/*template := linebot.NewButtonsTemplate(
				"", "", "Select date / time !",
				linebot.NewDatetimePickerTemplateAction("date", "DATE", "date", "", "", ""),
				linebot.NewDatetimePickerTemplateAction("time", "TIME", "time", "", "", ""),
				linebot.NewDatetimePickerTemplateAction("datetime", "DATETIME", "datetime", "", "", ""),
			)
			if _, err := bot.ReplyMessage(
				event.ReplyToken,
				linebot.NewTemplateMessage("Datetime pickers alt text", template),
			).Do(); err != nil {
				log.Print(err)
			}*/

		}

	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"bufio"
	"strconv"
	"log"
	"net"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func FetchId() int64 {

	res, err := db.Exec("UPDATE sequence SET id=LAST_INSERT_ID(id+1)")
	if err != nil {
		log.Fatal(err)
	}

	id, err := res.LastInsertId()

	log.Println("POP", id)
	if err != nil {
		log.Fatal(err)
	}
	return id
}

func handleRequest(conn net.Conn) {
	client := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
	defer conn.Close()

	cmd, err := client.ReadString('\n')
	// handle http requests
	for err == nil && cmd != "\r\n" {
		log.Print(strconv.QuoteToASCII(cmd))
		cmd, err = client.ReadString('\n')
	}

	if err != nil && err != io.EOF {
		log.Fatal("Error reading buffer:", err.Error())
	}

	id := FetchId()

	client.WriteString(strconv.FormatInt(id, 10))
	client.Flush()
	return
}

func main() {
	var err error
	user := flag.String("user", "root", "MySQL user")
	password := flag.String("password", "", "MySQL password")
	db_name := flag.String("database", "test", "MySQL database name")
	host := flag.String("host", "127.0.0.1", "MySQL host")
	port := flag.String("port", "3306", "MySQL port")
	flag.Parse()
	hostport := net.JoinHostPort(*host, *port)

	db, err = sql.Open("mysql", *user+":"+*password+"@tcp("+hostport+")/"+*db_name)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}

	_, err = db.Exec("CREATE TABLE sequence (id INT NOT NULL)")
	if err == nil {
		db.Exec("INSERT INTO sequence VALUES (0)")
	}

	socket, err := net.Listen("tcp", ":8000")
	if err != nil {
		log.Fatal(err)
	}
	defer socket.Close()

	for {
		conn, err := socket.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go handleRequest(conn)
	}
}
<commit_msg>Dont close the connection unless \r\n<commit_after>package main

import (
	"flag"
	"io"
	"bufio"
	"strconv"
	"log"
	"net"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func FetchId() int64 {

	res, err := db.Exec("UPDATE sequence SET id=LAST_INSERT_ID(id+1)")
	if err != nil {
		log.Fatal(err)
	}

	id, err := res.LastInsertId()

	log.Println("POP", id)
	if err != nil {
		log.Fatal(err)
	}
	return id
}

func handleRequest(conn net.Conn) {
	client := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
	defer conn.Close()

	cmd, err := client.ReadString('\n')

	for err == nil || err == io.EOF {
		log.Print(strconv.QuoteToASCII(cmd))
		switch cmd {
		case "GET / HTTP/1.1\r\n", "FETCH ID\r\n", "FETCH ID\n", "FETCH ID" :
			id := FetchId()
			client.WriteString(strconv.FormatInt(id, 10))
			client.WriteString("\n")
			client.Flush()
		case "\r\n":
			return
		}
		cmd, err = client.ReadString('\n')
		if err == io.EOF {
			return
		}
	}

	if err == io.EOF {
		log.Print("EOF")
		log.Print(cmd)
	}

	if err != nil && err != io.EOF {
		log.Fatal("Error reading buffer:", err.Error())
	}

	return
}

func main() {
	var err error
	user := flag.String("user", "root", "MySQL user")
	password := flag.String("password", "", "MySQL password")
	db_name := flag.String("database", "test", "MySQL database name")
	host := flag.String("host", "127.0.0.1", "MySQL host")
	port := flag.String("port", "3306", "MySQL port")
	flag.Parse()
	hostport := net.JoinHostPort(*host, *port)

	db, err = sql.Open("mysql", *user+":"+*password+"@tcp("+hostport+")/"+*db_name)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}

	_, err = db.Exec("CREATE TABLE sequence (id INT NOT NULL)")
	if err == nil {
		db.Exec("INSERT INTO sequence VALUES (0)")
	}

	socket, err := net.Listen("tcp", ":8000")
	if err != nil {
		log.Fatal(err)
	}
	defer socket.Close()

	for {
		conn, err := socket.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go handleRequest(conn)
	}
}
<|endoftext|>