<commit_before>package main

import (
	"fmt"
	"gnd.la/log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type State uint8

const (
	StateStopped State = iota
	StateStopping
	StateStarted
	StateStarting
	StateFailed
)

const (
	minTime = time.Second
)

type Service struct {
	sync.Mutex
	Config   *Config
	Cmd      *exec.Cmd
	State    State
	Started  time.Time
	Restarts int
	Err      error
	Ch       chan error
	logger   *logger
}

func newService(cfg *Config) *Service {
	return &Service{Config: cfg, Ch: make(chan error)}
}

func (s *Service) Name() string {
	return s.Config.ServiceName()
}

func (s *Service) initLogger() {
	var m monitor
	if s.logger != nil {
		s.logger.Close()
		m = s.logger.monitor
		s.logger = nil
	}
	logPath := filepath.Join(LogDir, s.Name()+".log.gz")
	f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Errorf("error opening log file %s: %s", logPath, err)
		return
	}
	s.logger = newLogger(f)
	s.logger.monitor = m
}

func (s *Service) sendErr(err error) bool {
	select {
	case s.Ch <- err:
		return true
	default:
	}
	return false
}

func (s *Service) Start() error {
	if err := s.startService(); err != nil {
		return err
	}
	if err := s.startWatchdog(); err != nil {
		log.Errorf("error starting %s's watchdog: %s", s.Name(), err)
	}
	return nil
}

func (s *Service) Run() {
	s.Lock()
	s.State = StateStarted
	s.initLogger()
	s.Unlock()
	for {
		s.Lock()
		name := s.Name()
		if s.State != StateStarted {
			s.Unlock()
			break
		}
		cmd, err := s.Config.Cmd()
		if err != nil {
			s.State = StateFailed
			s.Err = err
			log.Errorf("could not initialize %s: %s", name, err)
			s.Unlock()
			break
		}
		if s.logger != nil {
			cmd.Stdout = s.logger.stdout
			cmd.Stderr = s.logger.stderr
		}
		s.Cmd = cmd
		s.Started = time.Now()
		log.Infof("Starting %s", name)
		if err := s.Cmd.Start(); err != nil {
			s.State = StateFailed
			s.Err = err
			log.Errorf("failed to start %s: %s", name, err)
			s.Unlock()
			break
		}
		s.Unlock()
		time.AfterFunc(time.Duration(float64(minTime)*1.1), func() {
			s.Lock()
			defer s.Unlock()
			if s.Err == nil {
				s.sendErr(nil)
				log.Infof("Started %s", name)
			}
		})
		err = s.Cmd.Wait()
		s.Lock()
		if s.State != StateStarted {
			s.Cmd = nil
			s.sendErr(nil)
			s.Unlock()
			break
		}
		if since := time.Since(s.Started); since < minTime {
			// Consider failure
			s.Cmd = nil
			s.State = StateFailed
			s.Err = fmt.Errorf("exited too fast (%s)", since)
			s.sendErr(s.Err)
			s.Unlock()
			log.Errorf("%s %s", name, s.Err)
			break
		}
		s.Restarts++
		s.Unlock()
		log.Infof("%s exited with error %s - restarting", name, err)
	}
}

func (s *Service) Stop() error {
	s.stopWatchdog()
	if err := s.stopService(); err != nil {
		s.startWatchdog()
		return err
	}
	return nil
}

func (s *Service) startWatchdog() error {
	if s.Config.Watchdog != nil {
		interval := s.Config.WatchdogInterval
		if interval < 0 {
			interval = defaultWatchdogInterval
		}
		return s.Config.Watchdog.Start(s, interval)
	}
	return nil
}

func (s *Service) stopWatchdog() {
	if s.Config.Watchdog != nil {
		s.Config.Watchdog.Stop()
	}
}

func (s *Service) startService() error {
	go s.Run()
	return <-s.Ch
}

func (s *Service) stopService() error {
	s.Lock()
	s.State = StateStopping
	name := s.Name()
	cmd := s.Cmd
	s.Unlock()
	if cmd == nil {
		s.Lock()
		s.State = StateStopped
		s.Unlock()
		return nil
	}
	log.Infof("Stopping %s", name)
	if cmd.Process != nil {
		cmd.Process.Signal(os.Signal(syscall.SIGTERM))
	}
	stopped := false
	select {
	case <-s.Ch:
		stopped = true
	case <-time.After(10 * time.Second):
		if cmd.Process != nil {
			cmd.Process.Kill()
		}
	}
	if !stopped {
		select {
		case <-s.Ch:
		case <-time.After(2 * time.Second):
			s.Lock()
			s.State = StateStarted
			s.Unlock()
			err := fmt.Errorf("could not stop %s, probably stuck", name)
			log.Error(err)
			return err
		}
	}
	s.Lock()
	s.State = StateStopped
	s.Restarts = 0
	s.Unlock()
	log.Infof("Stopped %s", name)
	if s.logger != nil {
		s.logger.Close()
		s.logger = nil
	}
	return nil
}
<commit_msg>Log start/stop/restart info to each service's log<commit_after>package main

import (
	"fmt"
	"gnd.la/log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type State uint8

const (
	StateStopped State = iota
	StateStopping
	StateStarted
	StateStarting
	StateFailed
)

const (
	minTime = time.Second
)

type Service struct {
	sync.Mutex
	Config   *Config
	Cmd      *exec.Cmd
	State    State
	Started  time.Time
	Restarts int
	Err      error
	Ch       chan error
	logger   *logger
}

func newService(cfg *Config) *Service {
	return &Service{Config: cfg, Ch: make(chan error)}
}

func (s *Service) Name() string {
	return s.Config.ServiceName()
}

func (s *Service) initLogger() {
	var m monitor
	if s.logger != nil {
		s.logger.Close()
		m = s.logger.monitor
		s.logger = nil
	}
	logPath := filepath.Join(LogDir, s.Name()+".log.gz")
	f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		s.errorf("error opening log file %s: %s", logPath, err)
		return
	}
	s.logger = newLogger(f)
	s.logger.monitor = m
}

func (s *Service) sendErr(err error) bool {
	select {
	case s.Ch <- err:
		return true
	default:
	}
	return false
}

func (s *Service) Start() error {
	if err := s.startService(); err != nil {
		return err
	}
	if err := s.startWatchdog(); err != nil {
		s.errorf("error starting watchdog: %s", s.Name(), err)
	}
	return nil
}

func (s *Service) Run() {
	s.Lock()
	s.State = StateStarted
	s.initLogger()
	s.Unlock()
	for {
		s.Lock()
		if s.State != StateStarted {
			s.Unlock()
			break
		}
		cmd, err := s.Config.Cmd()
		if err != nil {
			s.State = StateFailed
			s.Err = err
			s.errorf("could not initialize: %s", err)
			s.Unlock()
			break
		}
		if s.logger != nil {
			cmd.Stdout = s.logger.stdout
			cmd.Stderr = s.logger.stderr
		}
		s.Cmd = cmd
		s.Started = time.Now()
		s.infof("starting")
		if err := s.Cmd.Start(); err != nil {
			s.State = StateFailed
			s.Err = err
			s.errorf("failed to start: %s", err)
			s.Unlock()
			break
		}
		s.Unlock()
		time.AfterFunc(time.Duration(float64(minTime)*1.1), func() {
			s.Lock()
			defer s.Unlock()
			if s.Err == nil {
				s.sendErr(nil)
				s.infof("started")
			}
		})
		err = s.Cmd.Wait()
		s.Lock()
		if s.State != StateStarted {
			s.Cmd = nil
			s.sendErr(nil)
			s.Unlock()
			break
		}
		if since := time.Since(s.Started); since < minTime {
			// Consider failure
			s.Cmd = nil
			s.State = StateFailed
			s.Err = fmt.Errorf("exited too fast (%s)", since)
			s.sendErr(s.Err)
			s.Unlock()
			s.errorf(s.Err.Error())
			break
		}
		s.Restarts++
		s.Unlock()
		s.infof("exited with error %s - restarting", err)
	}
}

func (s *Service) Stop() error {
	s.stopWatchdog()
	if err := s.stopService(); err != nil {
		s.startWatchdog()
		return err
	}
	return nil
}

func (s *Service) startWatchdog() error {
	if s.Config.Watchdog != nil {
		interval := s.Config.WatchdogInterval
		if interval < 0 {
			interval = defaultWatchdogInterval
		}
		return s.Config.Watchdog.Start(s, interval)
	}
	return nil
}

func (s *Service) stopWatchdog() {
	if s.Config.Watchdog != nil {
		s.Config.Watchdog.Stop()
	}
}

func (s *Service) startService() error {
	go s.Run()
	return <-s.Ch
}

func (s *Service) stopService() error {
	s.Lock()
	s.State = StateStopping
	cmd := s.Cmd
	s.Unlock()
	if cmd == nil {
		s.Lock()
		s.State = StateStopped
		s.Unlock()
		return nil
	}
	s.infof("stopping")
	if cmd.Process != nil {
		cmd.Process.Signal(os.Signal(syscall.SIGTERM))
	}
	stopped := false
	select {
	case <-s.Ch:
		stopped = true
	case <-time.After(10 * time.Second):
		if cmd.Process != nil {
			cmd.Process.Kill()
		}
	}
	if !stopped {
		select {
		case <-s.Ch:
		case <-time.After(2 * time.Second):
			s.Lock()
			s.State = StateStarted
			s.Unlock()
			err := fmt.Errorf("could not stop, probably stuck")
			s.errorf(err.Error())
			return err
		}
	}
	s.Lock()
	s.State = StateStopped
	s.Restarts = 0
	s.Unlock()
	s.infof("stopped")
	if s.logger != nil {
		s.logger.Close()
		s.logger = nil
	}
	return nil
}

func (s *Service) log(level log.LLevel, prefix string, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	log.Logf(level, "[%s] %s", s.Name(), msg)
	if s.logger != nil {
		s.logger.Write(prefix, []byte(msg))
	}
}

func (s *Service) errorf(format string, args ...interface{}) {
	s.log(log.LError, "error", format, args...)
}

func (s *Service) infof(format string, args ...interface{}) {
	s.log(log.LInfo, "info", format, args...)
}

func (s *Service) debugf(format string, args ...interface{}) {
	s.log(log.LDebug, "debug", format, args...)
}
<|endoftext|>


<commit_before>package cmdtest

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"syscall"
	"time"
	"strings"
)

type Session struct {
	Cmd *exec.Cmd

	Stdin io.WriteCloser

	stdout *Expector
	stderr *Expector

	exited chan int
}

type OutputWrapper func(io.Writer) io.Writer

func Start(cmd *exec.Cmd) (*Session, error) {
	return StartWrapped(cmd, noopWrapper, noopWrapper)
}

func StartWrapped(cmd *exec.Cmd, outWrapper OutputWrapper, errWrapper OutputWrapper) (*Session, error) {
	stdinOut, stdinIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	stdoutOut, stdoutIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	stderrOut, stderrIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	cmd.Stdin = stdinOut
	cmd.Stdout = outWrapper(stdoutIn)
	cmd.Stderr = errWrapper(stderrIn)

	outExpector := NewExpector(stdoutOut, 0)
	errExpector := NewExpector(stderrOut, 0)

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	exited := make(chan int, 1)

	go func() {
		cmd.Wait()
		exited <- cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()

		stdoutIn.Close()
		stderrIn.Close()
	}()

	return &Session{
		Cmd: cmd,

		Stdin: stdinIn,

		stdout: outExpector,
		stderr: errExpector,

		exited: exited,
	}, nil
}

func (s Session) ExpectOutput(pattern string) error {
	return s.stdout.Expect(pattern)
}

func (s Session) ExpectOutputBranches(branches ...ExpectBranch) error {
	return s.stdout.ExpectBranches(branches...)
}

func (s Session) ExpectOutputWithTimeout(pattern string, timeout time.Duration) error {
	return s.stdout.ExpectWithTimeout(pattern, timeout)
}

func (s Session) ExpectError(pattern string) error {
	return s.stderr.Expect(pattern)
}

func (s Session) ExpectErrorWithTimeout(pattern string, timeout time.Duration) error {
	return s.stderr.ExpectWithTimeout(pattern, timeout)
}

func (s Session) Wait(timeout time.Duration) (int, error) {
	select {
	case status := <-s.exited:
		return status, nil
	case <-time.After(timeout):
		return -1, fmt.Errorf("command did not exit: %s", strings.Join(s.Cmd.Args, " "))
	}
}

func (s Session) FullOutput() []byte {
	return s.stdout.FullOutput()
}

func (s Session) FullErrorOutput() []byte {
	return s.stderr.FullOutput()
}

func noopWrapper(out io.Writer) io.Writer {
	return out
}
<commit_msg>close exit status channel after exiting<commit_after>package cmdtest

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"
)

type Session struct {
	Cmd *exec.Cmd

	Stdin io.WriteCloser

	stdout *Expector
	stderr *Expector

	exited chan int
}

type OutputWrapper func(io.Writer) io.Writer

func Start(cmd *exec.Cmd) (*Session, error) {
	return StartWrapped(cmd, noopWrapper, noopWrapper)
}

func StartWrapped(cmd *exec.Cmd, outWrapper OutputWrapper, errWrapper OutputWrapper) (*Session, error) {
	stdinOut, stdinIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	stdoutOut, stdoutIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	stderrOut, stderrIn, err := os.Pipe()
	if err != nil {
		return nil, err
	}

	cmd.Stdin = stdinOut
	cmd.Stdout = outWrapper(stdoutIn)
	cmd.Stderr = errWrapper(stderrIn)

	outExpector := NewExpector(stdoutOut, 0)
	errExpector := NewExpector(stderrOut, 0)

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	exited := make(chan int, 1)

	go func() {
		cmd.Wait()

		exited <- cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
		close(exited)

		stdoutIn.Close()
		stderrIn.Close()
	}()

	return &Session{
		Cmd: cmd,

		Stdin: stdinIn,

		stdout: outExpector,
		stderr: errExpector,

		exited: exited,
	}, nil
}

func (s Session) ExpectOutput(pattern string) error {
	return s.stdout.Expect(pattern)
}

func (s Session) ExpectOutputBranches(branches ...ExpectBranch) error {
	return s.stdout.ExpectBranches(branches...)
}

func (s Session) ExpectOutputWithTimeout(pattern string, timeout time.Duration) error {
	return s.stdout.ExpectWithTimeout(pattern, timeout)
}

func (s Session) ExpectError(pattern string) error {
	return s.stderr.Expect(pattern)
}

func (s Session) ExpectErrorWithTimeout(pattern string, timeout time.Duration) error {
	return s.stderr.ExpectWithTimeout(pattern, timeout)
}

func (s Session) Wait(timeout time.Duration) (int, error) {
	select {
	case status := <-s.exited:
		return status, nil
	case <-time.After(timeout):
		return -1, fmt.Errorf("command did not exit: %s", strings.Join(s.Cmd.Args, " "))
	}
}

func (s Session) FullOutput() []byte {
	return s.stdout.FullOutput()
}

func (s Session) FullErrorOutput() []byte {
	return s.stderr.FullOutput()
}

func noopWrapper(out io.Writer) io.Writer {
	return out
}
<|endoftext|>


<commit_before>// +build darwin linux windows

package main

import (
	"encoding/binary"
	"log"
	"os"
	"time"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/exp/f32"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/gl"
)

type gameState struct {
	width    int
	height   int
	gl       gl.Context
	program  gl.Program
	buf      gl.Buffer
	position gl.Attrib
}

func main() {
	log.Print("main begin")

	slowPaint := len(os.Args) > 1
	log.Printf("slowPaint: %v", slowPaint)

	game := &gameState{}
	var frames int
	var paints int
	sec := time.Now().Second()

	app.Main(func(a app.App) {
		log.Print("app.Main begin")

	LOOP:
		for e := range a.Events() {
			switch t := a.Filter(e).(type) {
			case lifecycle.Event:
				log.Printf("Lifecycle: %v", t)

				if t.From > t.To && t.To == lifecycle.StageDead {
					log.Printf("lifecycle down to dead")
					break LOOP
				}

				if t.Crosses(lifecycle.StageAlive) == lifecycle.CrossOff {
					log.Printf("lifecycle cross down alive")
					break LOOP
				}

				switch t.Crosses(lifecycle.StageVisible) {
				case lifecycle.CrossOn:
					glc, isGL := t.DrawContext.(gl.Context)
					if !isGL {
						log.Printf("Lifecycle: visible: bad GL context")
						continue LOOP
					}
					game.start(glc)
					a.Send(paint.Event{}) // start drawing
				case lifecycle.CrossOff:
					game.stop()
				}

			case paint.Event:
				if t.External || game.gl == nil {
					// As we are actively painting as fast as
					// we can (usually 60 FPS), skip any paint
					// events sent by the system.
					continue
				}

				paints++ // events

				if now := time.Now().Second(); now != sec {
					log.Printf("fps: %d, paints: %d", frames, paints)
					frames = 0
					paints = 0
					sec = now
				}

				if !slowPaint || frames == 0 {
					frames++ // draws
					game.paint()
					a.Publish()
				}

				if slowPaint {
					time.Sleep(500 * time.Millisecond)
				}

				// we request next paint event
				// in order to draw as fast as possible
				a.Send(paint.Event{})
			case mouse.Event:
				game.input(t.X, t.Y)
			case touch.Event:
				game.input(t.X, t.Y)
			case size.Event:
				game.resize(t.WidthPx, t.HeightPx)
			}
		}

		log.Print("app.Main end")
	})

	log.Print("main end")
}

func (game *gameState) resize(w, h int) {
	if game.width != w || game.height != h {
		log.Printf("resize: %d,%d", w, h)
	}
	game.width = w
	game.height = h
}

func (game *gameState) input(x, y float32) {
	log.Printf("input: %f,%f (%d x %d)", x, y, game.width, game.height)
}

func (game *gameState) start(glc gl.Context) {
	log.Printf("start")

	var err error
	game.program, err = glutil.CreateProgram(glc, vertexShader, fragmentShader)
	if err != nil {
		log.Printf("start: error creating GL program: %v", err)
		return
	}

	log.Printf("start: shader compiled")

	game.buf = glc.CreateBuffer()
	glc.BindBuffer(gl.ARRAY_BUFFER, game.buf)
	glc.BufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW)

	game.position = glc.GetAttribLocation(game.program, "position")

	game.gl = glc
}

func (game *gameState) stop() {
	log.Printf("stop")

	glc := game.gl // shortcut

	glc.DeleteProgram(game.program)
	glc.DeleteBuffer(game.buf)

	game.gl = nil
}

func (game *gameState) paint() {
	//log.Printf("paint: call OpenGL here")
	glc := game.gl // shortcut

	glc.ClearColor(.5, .5, .5, 1) // gray background
	glc.Clear(gl.COLOR_BUFFER_BIT)

	glc.UseProgram(game.program)

	glc.BindBuffer(gl.ARRAY_BUFFER, game.buf)
	glc.EnableVertexAttribArray(game.position)
	glc.VertexAttribPointer(game.position, coordsPerVertex, gl.FLOAT, false, 0, 0)
	glc.DrawArrays(gl.TRIANGLES, 0, vertexCount)
	glc.DisableVertexAttribArray(game.position)
}

const (
	coordsPerVertex = 3
	vertexCount     = 3
)

var triangleData = f32.Bytes(binary.LittleEndian,
	0.0, 0.4, 0.0, // top left
	0.0, 0.0, 0.0, // bottom left
	0.4, 0.0, 0.0, // bottom right
)

const vertexShader = `#version 100
attribute vec4 position;
void main() {
	gl_Position = position;
}`

const fragmentShader = `#version 100
precision mediump float;
void main() {
	gl_FragColor = vec4(0.8,0.8,0.8,1.0); // white
}`
<commit_msg>Comment.<commit_after>// +build darwin linux windows

package main

import (
	"encoding/binary"
	"log"
	"os"
	"time"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/exp/f32"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/gl"
)

type gameState struct {
	width    int
	height   int
	gl       gl.Context
	program  gl.Program
	buf      gl.Buffer
	position gl.Attrib
}

func main() {
	log.Print("main begin")

	slowPaint := len(os.Args) > 1
	log.Printf("slowPaint: %v", slowPaint)

	game := &gameState{}
	var frames int
	var paints int
	sec := time.Now().Second()

	app.Main(func(a app.App) {
		log.Print("app.Main begin")

	LOOP:
		for e := range a.Events() {
			switch t := a.Filter(e).(type) {
			case lifecycle.Event:
				log.Printf("Lifecycle: %v", t)

				if t.From > t.To && t.To == lifecycle.StageDead {
					log.Printf("lifecycle down to dead")
					break LOOP
				}

				if t.Crosses(lifecycle.StageAlive) == lifecycle.CrossOff {
					log.Printf("lifecycle cross down alive")
					break LOOP
				}

				switch t.Crosses(lifecycle.StageVisible) {
				case lifecycle.CrossOn:
					glc, isGL := t.DrawContext.(gl.Context)
					if !isGL {
						log.Printf("Lifecycle: visible: bad GL context")
						continue LOOP
					}
					game.start(glc)
					a.Send(paint.Event{}) // start drawing
				case lifecycle.CrossOff:
					game.stop()
				}

			case paint.Event:
				if t.External || game.gl == nil {
					// As we are actively painting as fast as
					// we can (usually 60 FPS), skip any paint
					// events sent by the system.
					continue
				}

				paints++ // events

				if now := time.Now().Second(); now != sec {
					log.Printf("fps: %d, paints: %d", frames, paints)
					frames = 0
					paints = 0
					sec = now
				}

				if !slowPaint || frames == 0 {
					frames++ // draws
					game.paint()
					a.Publish()
				}

				if slowPaint {
					time.Sleep(500 * time.Millisecond)
				}

				// we request next paint event
				// in order to draw as fast as possible
				a.Send(paint.Event{})
			case mouse.Event:
				game.input(t.X, t.Y)
			case touch.Event:
				game.input(t.X, t.Y)
			case size.Event:
				game.resize(t.WidthPx, t.HeightPx)
			}
		}

		log.Print("app.Main end")
	})

	log.Print("main end")
}

func (game *gameState) resize(w, h int) {
	if game.width != w || game.height != h {
		log.Printf("resize: %d,%d", w, h)
	}
	game.width = w
	game.height = h
}

func (game *gameState) input(x, y float32) {
	log.Printf("input: %f,%f (%d x %d)", x, y, game.width, game.height)
}

func (game *gameState) start(glc gl.Context) {
	log.Printf("start")

	var err error
	game.program, err = glutil.CreateProgram(glc, vertexShader, fragmentShader)
	if err != nil {
		log.Printf("start: error creating GL program: %v", err)
		return
	}

	log.Printf("start: shader compiled")

	game.buf = glc.CreateBuffer()
	glc.BindBuffer(gl.ARRAY_BUFFER, game.buf)
	glc.BufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW)

	game.position = glc.GetAttribLocation(game.program, "position")

	game.gl = glc
}

func (game *gameState) stop() {
	log.Printf("stop")

	glc := game.gl // shortcut

	glc.DeleteProgram(game.program)
	glc.DeleteBuffer(game.buf)

	game.gl = nil
}

func (game *gameState) paint() {
	//log.Printf("paint: call OpenGL here")
	glc := game.gl // shortcut

	glc.ClearColor(.5, .5, .5, 1) // gray background
	glc.Clear(gl.COLOR_BUFFER_BIT)

	glc.UseProgram(game.program)
	glc.EnableVertexAttribArray(game.position)

	glc.BindBuffer(gl.ARRAY_BUFFER, game.buf)

	// how to get data for location attribute within buffer
	glc.VertexAttribPointer(game.position, coordsPerVertex, gl.FLOAT, false, 0, 0)

	glc.DrawArrays(gl.TRIANGLES, 0, vertexCount)

	glc.DisableVertexAttribArray(game.position)
}

const (
	coordsPerVertex = 3
	vertexCount     = 3
)

var triangleData = f32.Bytes(binary.LittleEndian,
	0.0, 0.4, 0.0, // top left
	0.0, 0.0, 0.0, // bottom left
	0.4, 0.0, 0.0, // bottom right
)

const vertexShader = `#version 100
attribute vec4 position;
void main() {
	gl_Position = position;
}`

const fragmentShader = `#version 100
precision mediump float;
void main() {
	gl_FragColor = vec4(0.8,0.8,0.8,1.0); // white
}`
<|endoftext|>


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

package geddit

import (
	"encoding/json"
	"fmt"
	"image"
	"image/png"

	"github.com/google/go-querystring/query"
)

// Session represents an HTTP session with reddit.com
// without logging into an account.
type Session struct {
	useragent string
}

// NewSession creates a new unauthenticated session to reddit.com.
func NewSession(useragent string) *Session {
	return &Session{
		useragent: useragent,
	}
}

// DefaultFrontpage returns the submissions on the default reddit frontpage.
func (s Session) DefaultFrontpage(sort PopularitySort, params ListingOptions) ([]*Submission, error) {
	return s.SubredditSubmissions("", sort, params)
}

// SubredditSubmissions returns the submissions on the given subreddit.
func (s Session) SubredditSubmissions(subreddit string, sort PopularitySort, params ListingOptions) ([]*Submission, error) {
	v, err := query.Values(params)
	if err != nil {
		return nil, err
	}

	baseUrl := "https://www.reddit.com"

	// If subbreddit given, add to URL
	if subreddit != "" {
		baseUrl += "/r/" + subreddit
	}

	redditUrl := fmt.Sprintf(baseUrl+"/%s.json?%s", sort, v.Encode())

	req := request{
		url:       redditUrl,
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data struct {
			Children []struct {
				Data *Submission
			}
		}
	}

	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	submissions := make([]*Submission, len(r.Data.Children))
	for i, child := range r.Data.Children {
		submissions[i] = child.Data
	}

	return submissions, nil
}

// AboutRedditor returns a Redditor for the given username.
func (s Session) AboutRedditor(username string) (*Redditor, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/user/%s/about.json", username),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data Redditor
	}
	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	return &r.Data, nil
}

// AboutSubreddit returns a subreddit for the given subreddit name.
func (s Session) AboutSubreddit(subreddit string) (*Subreddit, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/r/%s/about.json", subreddit),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data Subreddit
	}

	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	return &r.Data, nil
}

// Comments returns the comments for a given Submission.
func (s Session) Comments(h *Submission) ([]*Comment, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/comments/%s/.json", h.ID),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	r := json.NewDecoder(body)
	var interf interface{}
	if err = r.Decode(&interf); err != nil {
		return nil, err
	}
	helper := new(helper)
	helper.buildComments(interf)

	return helper.comments, nil
}

// CaptchaImage gets the png corresponding to the captcha iden and decodes it
func (s Session) CaptchaImage(iden string) (image.Image, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/captcha/%s", iden),
		useragent: s.useragent,
	}

	p, err := req.getResponse()

	if err != nil {
		return nil, err
	}

	m, err := png.Decode(p)

	if err != nil {
		return nil, err
	}

	return m, nil
}
<commit_msg>Added SubredditComments for a Session<commit_after>// Copyright 2012 Jimmy Zelinskie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package geddit

import (
	"encoding/json"
	"fmt"
	"image"
	"image/png"

	"github.com/google/go-querystring/query"
)

// Session represents an HTTP session with reddit.com
// without logging into an account.
type Session struct {
	useragent string
}

// NewSession creates a new unauthenticated session to reddit.com.
func NewSession(useragent string) *Session {
	return &Session{
		useragent: useragent,
	}
}

// DefaultFrontpage returns the submissions on the default reddit frontpage.
func (s Session) DefaultFrontpage(sort PopularitySort, params ListingOptions) ([]*Submission, error) {
	return s.SubredditSubmissions("", sort, params)
}

// SubredditSubmissions returns the submissions on the given subreddit.
func (s Session) SubredditSubmissions(subreddit string, sort PopularitySort, params ListingOptions) ([]*Submission, error) {
	v, err := query.Values(params)
	if err != nil {
		return nil, err
	}

	baseUrl := "https://www.reddit.com"

	// If subbreddit given, add to URL
	if subreddit != "" {
		baseUrl += "/r/" + subreddit
	}

	redditUrl := fmt.Sprintf(baseUrl+"/%s.json?%s", sort, v.Encode())

	req := request{
		url:       redditUrl,
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data struct {
			Children []struct {
				Data *Submission
			}
		}
	}

	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	submissions := make([]*Submission, len(r.Data.Children))
	for i, child := range r.Data.Children {
		submissions[i] = child.Data
	}

	return submissions, nil
}

// AboutRedditor returns a Redditor for the given username.
func (s Session) AboutRedditor(username string) (*Redditor, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/user/%s/about.json", username),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data Redditor
	}
	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	return &r.Data, nil
}

// AboutSubreddit returns a subreddit for the given subreddit name.
func (s Session) AboutSubreddit(subreddit string) (*Subreddit, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/r/%s/about.json", subreddit),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	type Response struct {
		Data Subreddit
	}

	r := new(Response)
	err = json.NewDecoder(body).Decode(r)
	if err != nil {
		return nil, err
	}

	return &r.Data, nil
}

// Comments returns the comments for a given Submission.
func (s Session) Comments(h *Submission) ([]*Comment, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/comments/%s/.json", h.ID),
		useragent: s.useragent,
	}
	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	r := json.NewDecoder(body)
	var interf interface{}
	if err = r.Decode(&interf); err != nil {
		return nil, err
	}
	helper := new(helper)
	helper.buildComments(interf)

	return helper.comments, nil
}

// CaptchaImage gets the png corresponding to the captcha iden and decodes it
func (s Session) CaptchaImage(iden string) (image.Image, error) {
	req := &request{
		url:       fmt.Sprintf("https://www.reddit.com/captcha/%s", iden),
		useragent: s.useragent,
	}

	p, err := req.getResponse()

	if err != nil {
		return nil, err
	}

	m, err := png.Decode(p)

	if err != nil {
		return nil, err
	}

	return m, nil
}

func (s Session) SubredditComments(subreddit string) ([]*Comment, error) {
	baseURL := "https://www.reddit.com"

	if subreddit != "" {
		baseURL += "/r/" + subreddit
	}

	subCommentsURL = baseURL + "/comments.json"

	req := request{
		url:       subCommentsURL,
		useragent: s.useragent,
	}

	body, err := req.getResponse()
	if err != nil {
		return nil, err
	}

	var comments interface{}
	if err = json.NewDecoder(body).Decode(&comments); err != nil {
		return nil, err
	}
	helper := new(helper)
	helper.buildComments(comments)

	return helper.comments, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Beego Authors
// Copyright 2014 Unknwon
//
// 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 session a middleware that provides the session manager of Macaron.
package session

// NOTE: last sync a144769 on Aug 18, 2014.

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"

	"github.com/Unknwon/macaron"
)

func Version() string {
	return "0.0.2"
}

type RawStore interface {
	Set(key, value interface{}) error     //set session value
	Get(key interface{}) interface{}      //get session value
	Delete(key interface{}) error         //delete session value
	SessionID() string                    //back current sessionID
	SessionRelease(w http.ResponseWriter) // release the resource & save data to provider & return the data
	Flush() error                         //delete all data
}

// Store contains all data for one session process with specific id.
type Store interface {
	RawStore
	GetActiveSession() int
}

type Options struct {
	// Name of provider. Default is memory.
	Provider string
	// Provider configuration string.
	Config
}

func prepareOptions(options []Options) Options {
	var opt Options
	if len(options) > 0 {
		opt = options[0]
	}

	// Defaults
	if len(opt.Provider) == 0 {
		opt.Provider = "memory"
	}
	opt.EnableSetCookie = true
	if len(opt.CookieName) == 0 {
		opt.CookieName = "macaronSession"
	}
	if len(opt.CookiePath) == 0 {
		opt.CookiePath = "/"
	}
	if opt.Gclifetime == 0 {
		opt.Gclifetime = 3600
	}
	if opt.Maxlifetime == 0 {
		opt.Maxlifetime = opt.Gclifetime
	}
	if opt.SessionIDHashFunc == "" {
		opt.SessionIDHashFunc = "sha1"
	}
	if opt.SessionIDHashKey == "" {
		opt.SessionIDHashKey = string(generateRandomKey(16))
	}

	return opt
}

// ___________.____       _____    _________ ___ ___
// \_   _____/|    |     /  _  \  /   _____//   |   \
//  |    __)  |    |    /  /_\  \ \_____  \/    ~    \
//  |     \   |    |___/    |    \/        \    Y    /
//  \___  /   |_______ \____|__  /_______  /\___|_  /
//      \/            \/       \/        \/       \/

type Flash struct {
	ctx *macaron.Context
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string, current ...bool) {
	isShow := false
	if len(current) > 0 && current[0] {
		isShow = true
	}

	if isShow {
		f.ctx.Data["Flash"] = f
	} else {
		f.Set(name, msg)
	}
}

func (f *Flash) Error(msg string, current ...bool) {
	f.ErrorMsg = msg
	f.set("error", msg, current...)
}

func (f *Flash) Warning(msg string, current ...bool) {
	f.WarningMsg = msg
	f.set("warning", msg, current...)
}

func (f *Flash) Info(msg string, current ...bool) {
	f.InfoMsg = msg
	f.set("info", msg, current...)
}

func (f *Flash) Success(msg string, current ...bool) {
	f.SuccessMsg = msg
	f.set("success", msg, current...)
}

type store struct {
	RawStore
	*Manager
}

// Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain.
// An single variadic session.Options struct can be optionally provided to configure.
func Sessioner(options ...Options) macaron.Handler {
	opt := prepareOptions(options)
	manager, err := NewManager(opt.Provider, &opt.Config)
	if err != nil {
		panic(err)
	}
	go manager.GC()

	return func(ctx *macaron.Context) {
		sess := manager.SessionStart(ctx.Resp, ctx.Req)

		// Get flash.
		vals, _ := url.ParseQuery(ctx.GetCookie("macaron_flash"))
		if len(vals) > 0 {
			f := &Flash{Values: vals}
			f.ErrorMsg = f.Get("error")
			f.SuccessMsg = f.Get("success")
			f.InfoMsg = f.Get("info")
			f.WarningMsg = f.Get("warning")
			ctx.Data["Flash"] = f
			ctx.SetCookie("macaron_flash", "", -1, opt.CookiePath)
		}

		f := &Flash{ctx, url.Values{}, "", "", "", ""}
		ctx.Resp.Before(func(macaron.ResponseWriter) {
			sess.SessionRelease(ctx.Resp)

			if flash := f.Encode(); len(flash) > 0 {
				ctx.SetCookie("macaron_flash", flash, 0, opt.CookiePath)
			}
		})

		ctx.Map(f)
		s := store{
			RawStore: sess,
			Manager:  manager,
		}
		ctx.MapTo(s, (*Store)(nil))
	}
}

// Provider contains global session methods and saved SessionStores.
// it can operate a SessionStore by its id.
type Provider interface {
	SessionInit(gclifetime int64, config string) error
	SessionRead(sid string) (RawStore, error)
	SessionExist(sid string) bool
	SessionRegenerate(oldsid, sid string) (RawStore, error)
	SessionDestroy(sid string) error
	SessionAll() int //get all active session
	SessionGC()
}

var provides = make(map[string]Provider)

// Register makes a session provide available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, provide Provider) {
	if provide == nil {
		panic("session: Register provide is nil")
	}
	if _, dup := provides[name]; dup {
		panic("session: Register called twice for provider " + name)
	}
	provides[name] = provide
}

type Config struct {
	CookieName        string `json:"cookieName"`
	CookiePath        string `json:"cookiePath"`
	EnableSetCookie   bool   `json:"enableSetCookie,omitempty"`
	Gclifetime        int64  `json:"gclifetime"`
	Maxlifetime       int64  `json:"maxLifetime"`
	Secure            bool   `json:"secure"`
	SessionIDHashFunc string `json:"sessionIDHashFunc"`
	SessionIDHashKey  string `json:"sessionIDHashKey"`
	CookieLifeTime    int    `json:"cookieLifeTime"`
	ProviderConfig    string `json:"providerConfig"`
	Domain            string `json:"domain"`
}

// Manager contains Provider and its configuration.
type Manager struct {
	provider Provider
	config   *Config
}

// Create new Manager with provider name and json config string.
// provider name:
// 1. cookie
// 2. file
// 3. memory
// 4. redis
// 5. mysql
// json config:
// 1. is https  default false
// 2. hashfunc  default sha1
// 3. hashkey default beegosessionkey
// 4. maxage default is none
func NewManager(provideName string, config *Config) (*Manager, error) {
	provider, ok := provides[provideName]
	if !ok {
		return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName)
	}

	config.EnableSetCookie = true
	if config.Maxlifetime == 0 {
		config.Maxlifetime = config.Gclifetime
	}
	if err := provider.SessionInit(config.Maxlifetime, config.ProviderConfig); err != nil {
		return nil, err
	}
	return &Manager{
		provider: provider,
		config:   config,
	}, nil
}

// Start session. generate or read the session id from http request.
// if session id exists, return SessionStore with this id.
func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session RawStore) {
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil || cookie.Value == "" {
		sid := manager.sessionId(r)
		session, _ = manager.provider.SessionRead(sid)
		cookie = &http.Cookie{Name: manager.config.CookieName,
			Value:    url.QueryEscape(sid),
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Secure:   manager.config.Secure,
			Domain:   manager.config.Domain,
		}
		if manager.config.CookieLifeTime >= 0 {
			cookie.MaxAge = manager.config.CookieLifeTime
		}
		if manager.config.EnableSetCookie {
			http.SetCookie(w, cookie)
		}
		r.AddCookie(cookie)
	} else {
		sid, _ := url.QueryUnescape(cookie.Value)
		if manager.provider.SessionExist(sid) {
			session, _ = manager.provider.SessionRead(sid)
		} else {
			sid = manager.sessionId(r)
			session, _ = manager.provider.SessionRead(sid)
			cookie = &http.Cookie{Name: manager.config.CookieName,
				Value:    url.QueryEscape(sid),
				Path:     manager.config.CookiePath,
				HttpOnly: true,
				Secure:   manager.config.Secure,
				Domain:   manager.config.Domain,
			}
			if manager.config.CookieLifeTime >= 0 {
				cookie.MaxAge = manager.config.CookieLifeTime
			}
			if manager.config.EnableSetCookie {
				http.SetCookie(w, cookie)
			}
			r.AddCookie(cookie)
		}
	}
	return session
}

// Destroy session by its id in http request cookie.
func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil || cookie.Value == "" {
		return
	} else {
		manager.provider.SessionDestroy(cookie.Value)
		expiration := time.Now()
		cookie := http.Cookie{Name: manager.config.CookieName,
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Expires:  expiration,
			MaxAge:   -1}
		http.SetCookie(w, &cookie)
	}
}

// Get SessionStore by its id.
func (manager *Manager) GetSessionStore(sid string) (sessions RawStore, err error) {
	sessions, err = manager.provider.SessionRead(sid)
	return
}

// Start session gc process.
// it can do gc in times after gc lifetime.
func (manager *Manager) GC() {
	manager.provider.SessionGC()
	time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() })
}

// Regenerate a session id for this SessionStore who's id is saving in http request.
func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session RawStore) {
	sid := manager.sessionId(r)
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil && cookie.Value == "" {
		//delete old cookie
		session, _ = manager.provider.SessionRead(sid)
		cookie = &http.Cookie{Name: manager.config.CookieName,
			Value:    url.QueryEscape(sid),
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Secure:   manager.config.Secure,
			Domain:   manager.config.Domain,
		}
	} else {
		oldsid, _ := url.QueryUnescape(cookie.Value)
		session, _ = manager.provider.SessionRegenerate(oldsid, sid)
		cookie.Value = url.QueryEscape(sid)
		cookie.HttpOnly = true
		cookie.Path = "/"
	}
	if manager.config.CookieLifeTime >= 0 {
		cookie.MaxAge = manager.config.CookieLifeTime
	}
	http.SetCookie(w, cookie)
	r.AddCookie(cookie)
	return
}

// Get all active sessions count number.
func (manager *Manager) GetActiveSession() int {
	return manager.provider.SessionAll()
}

// Set hash function for generating session id.
func (manager *Manager) SetHashFunc(hasfunc, hashkey string) {
	manager.config.SessionIDHashFunc = hasfunc
	manager.config.SessionIDHashKey = hashkey
}

// Set cookie with https.
func (manager *Manager) SetSecure(secure bool) {
	manager.config.Secure = secure
}

// generate session id with rand string, unix nano time, remote addr by hash function.
func (manager *Manager) sessionId(r *http.Request) (sid string) {
	bs := make([]byte, 32)
	if n, err := io.ReadFull(rand.Reader, bs); n != 32 || err != nil {
		bs = RandomCreateBytes(32)
	}
	sig := fmt.Sprintf("%s%d%s", r.RemoteAddr, time.Now().UnixNano(), bs)
	if manager.config.SessionIDHashFunc == "md5" {
		h := md5.New()
		h.Write([]byte(sig))
		sid = hex.EncodeToString(h.Sum(nil))
	} else if manager.config.SessionIDHashFunc == "sha1" {
		h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey))
		fmt.Fprintf(h, "%s", sig)
		sid = hex.EncodeToString(h.Sum(nil))
	} else {
		h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey))
		fmt.Fprintf(h, "%s", sig)
		sid = hex.EncodeToString(h.Sum(nil))
	}
	return
}
<commit_msg>Able to use FlashNow in core lib<commit_after>// Copyright 2013 Beego Authors
// Copyright 2014 Unknwon
//
// 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 session a middleware that provides the session manager of Macaron.
package session

// NOTE: last sync a144769 on Aug 18, 2014.

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"

	"github.com/Unknwon/macaron"
)

func Version() string {
	return "0.0.2"
}

type RawStore interface {
	Set(key, value interface{}) error     //set session value
	Get(key interface{}) interface{}      //get session value
	Delete(key interface{}) error         //delete session value
	SessionID() string                    //back current sessionID
	SessionRelease(w http.ResponseWriter) // release the resource & save data to provider & return the data
	Flush() error                         //delete all data
}

// Store contains all data for one session process with specific id.
type Store interface {
	RawStore
	GetActiveSession() int
}

type Options struct {
	// Name of provider. Default is memory.
	Provider string
	// Provider configuration string.
	Config
}

func prepareOptions(options []Options) Options {
	var opt Options
	if len(options) > 0 {
		opt = options[0]
	}

	// Defaults
	if len(opt.Provider) == 0 {
		opt.Provider = "memory"
	}
	opt.EnableSetCookie = true
	if len(opt.CookieName) == 0 {
		opt.CookieName = "macaronSession"
	}
	if len(opt.CookiePath) == 0 {
		opt.CookiePath = "/"
	}
	if opt.Gclifetime == 0 {
		opt.Gclifetime = 3600
	}
	if opt.Maxlifetime == 0 {
		opt.Maxlifetime = opt.Gclifetime
	}
	if opt.SessionIDHashFunc == "" {
		opt.SessionIDHashFunc = "sha1"
	}
	if opt.SessionIDHashKey == "" {
		opt.SessionIDHashKey = string(generateRandomKey(16))
	}

	return opt
}

// ___________.____       _____    _________ ___ ___
// \_   _____/|    |     /  _  \  /   _____//   |   \
//  |    __)  |    |    /  /_\  \ \_____  \/    ~    \
//  |     \   |    |___/    |    \/        \    Y    /
//  \___  /   |_______ \____|__  /_______  /\___|_  /
//      \/            \/       \/        \/       \/

type Flash struct {
	ctx *macaron.Context
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string, current ...bool) {
	isShow := false
	if (len(current) == 0 && macaron.FlashNow) ||
		(len(current) > 0 && current[0]) {
		isShow = true
	}

	if isShow {
		f.ctx.Data["Flash"] = f
	} else {
		f.Set(name, msg)
	}
}

func (f *Flash) Error(msg string, current ...bool) {
	f.ErrorMsg = msg
	f.set("error", msg, current...)
}

func (f *Flash) Warning(msg string, current ...bool) {
	f.WarningMsg = msg
	f.set("warning", msg, current...)
}

func (f *Flash) Info(msg string, current ...bool) {
	f.InfoMsg = msg
	f.set("info", msg, current...)
}

func (f *Flash) Success(msg string, current ...bool) {
	f.SuccessMsg = msg
	f.set("success", msg, current...)
}

type store struct {
	RawStore
	*Manager
}

// Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain.
// An single variadic session.Options struct can be optionally provided to configure.
func Sessioner(options ...Options) macaron.Handler {
	opt := prepareOptions(options)
	manager, err := NewManager(opt.Provider, &opt.Config)
	if err != nil {
		panic(err)
	}
	go manager.GC()

	return func(ctx *macaron.Context) {
		sess := manager.SessionStart(ctx.Resp, ctx.Req)

		// Get flash.
		vals, _ := url.ParseQuery(ctx.GetCookie("macaron_flash"))
		if len(vals) > 0 {
			f := &Flash{Values: vals}
			f.ErrorMsg = f.Get("error")
			f.SuccessMsg = f.Get("success")
			f.InfoMsg = f.Get("info")
			f.WarningMsg = f.Get("warning")
			ctx.Data["Flash"] = f
			ctx.SetCookie("macaron_flash", "", -1, opt.CookiePath)
		}

		f := &Flash{ctx, url.Values{}, "", "", "", ""}
		ctx.Resp.Before(func(macaron.ResponseWriter) {
			sess.SessionRelease(ctx.Resp)

			if flash := f.Encode(); len(flash) > 0 {
				ctx.SetCookie("macaron_flash", flash, 0, opt.CookiePath)
			}
		})

		ctx.Map(f)
		s := store{
			RawStore: sess,
			Manager:  manager,
		}
		ctx.MapTo(s, (*Store)(nil))
	}
}

// Provider contains global session methods and saved SessionStores.
// it can operate a SessionStore by its id.
type Provider interface {
	SessionInit(gclifetime int64, config string) error
	SessionRead(sid string) (RawStore, error)
	SessionExist(sid string) bool
	SessionRegenerate(oldsid, sid string) (RawStore, error)
	SessionDestroy(sid string) error
	SessionAll() int //get all active session
	SessionGC()
}

var provides = make(map[string]Provider)

// Register makes a session provide available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, provide Provider) {
	if provide == nil {
		panic("session: Register provide is nil")
	}
	if _, dup := provides[name]; dup {
		panic("session: Register called twice for provider " + name)
	}
	provides[name] = provide
}

type Config struct {
	CookieName        string `json:"cookieName"`
	CookiePath        string `json:"cookiePath"`
	EnableSetCookie   bool   `json:"enableSetCookie,omitempty"`
	Gclifetime        int64  `json:"gclifetime"`
	Maxlifetime       int64  `json:"maxLifetime"`
	Secure            bool   `json:"secure"`
	SessionIDHashFunc string `json:"sessionIDHashFunc"`
	SessionIDHashKey  string `json:"sessionIDHashKey"`
	CookieLifeTime    int    `json:"cookieLifeTime"`
	ProviderConfig    string `json:"providerConfig"`
	Domain            string `json:"domain"`
}

// Manager contains Provider and its configuration.
type Manager struct {
	provider Provider
	config   *Config
}

// Create new Manager with provider name and json config string.
// provider name:
// 1. cookie
// 2. file
// 3. memory
// 4. redis
// 5. mysql
// json config:
// 1. is https  default false
// 2. hashfunc  default sha1
// 3. hashkey default beegosessionkey
// 4. maxage default is none
func NewManager(provideName string, config *Config) (*Manager, error) {
	provider, ok := provides[provideName]
	if !ok {
		return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName)
	}

	config.EnableSetCookie = true
	if config.Maxlifetime == 0 {
		config.Maxlifetime = config.Gclifetime
	}
	if err := provider.SessionInit(config.Maxlifetime, config.ProviderConfig); err != nil {
		return nil, err
	}
	return &Manager{
		provider: provider,
		config:   config,
	}, nil
}

// Start session. generate or read the session id from http request.
// if session id exists, return SessionStore with this id.
func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session RawStore) {
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil || cookie.Value == "" {
		sid := manager.sessionId(r)
		session, _ = manager.provider.SessionRead(sid)
		cookie = &http.Cookie{Name: manager.config.CookieName,
			Value:    url.QueryEscape(sid),
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Secure:   manager.config.Secure,
			Domain:   manager.config.Domain,
		}
		if manager.config.CookieLifeTime >= 0 {
			cookie.MaxAge = manager.config.CookieLifeTime
		}
		if manager.config.EnableSetCookie {
			http.SetCookie(w, cookie)
		}
		r.AddCookie(cookie)
	} else {
		sid, _ := url.QueryUnescape(cookie.Value)
		if manager.provider.SessionExist(sid) {
			session, _ = manager.provider.SessionRead(sid)
		} else {
			sid = manager.sessionId(r)
			session, _ = manager.provider.SessionRead(sid)
			cookie = &http.Cookie{Name: manager.config.CookieName,
				Value:    url.QueryEscape(sid),
				Path:     manager.config.CookiePath,
				HttpOnly: true,
				Secure:   manager.config.Secure,
				Domain:   manager.config.Domain,
			}
			if manager.config.CookieLifeTime >= 0 {
				cookie.MaxAge = manager.config.CookieLifeTime
			}
			if manager.config.EnableSetCookie {
				http.SetCookie(w, cookie)
			}
			r.AddCookie(cookie)
		}
	}
	return session
}

// Destroy session by its id in http request cookie.
func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil || cookie.Value == "" {
		return
	} else {
		manager.provider.SessionDestroy(cookie.Value)
		expiration := time.Now()
		cookie := http.Cookie{Name: manager.config.CookieName,
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Expires:  expiration,
			MaxAge:   -1}
		http.SetCookie(w, &cookie)
	}
}

// Get SessionStore by its id.
func (manager *Manager) GetSessionStore(sid string) (sessions RawStore, err error) {
	sessions, err = manager.provider.SessionRead(sid)
	return
}

// Start session gc process.
// it can do gc in times after gc lifetime.
func (manager *Manager) GC() {
	manager.provider.SessionGC()
	time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() })
}

// Regenerate a session id for this SessionStore who's id is saving in http request.
func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session RawStore) {
	sid := manager.sessionId(r)
	cookie, err := r.Cookie(manager.config.CookieName)
	if err != nil && cookie.Value == "" {
		//delete old cookie
		session, _ = manager.provider.SessionRead(sid)
		cookie = &http.Cookie{Name: manager.config.CookieName,
			Value:    url.QueryEscape(sid),
			Path:     manager.config.CookiePath,
			HttpOnly: true,
			Secure:   manager.config.Secure,
			Domain:   manager.config.Domain,
		}
	} else {
		oldsid, _ := url.QueryUnescape(cookie.Value)
		session, _ = manager.provider.SessionRegenerate(oldsid, sid)
		cookie.Value = url.QueryEscape(sid)
		cookie.HttpOnly = true
		cookie.Path = "/"
	}
	if manager.config.CookieLifeTime >= 0 {
		cookie.MaxAge = manager.config.CookieLifeTime
	}
	http.SetCookie(w, cookie)
	r.AddCookie(cookie)
	return
}

// Get all active sessions count number.
func (manager *Manager) GetActiveSession() int {
	return manager.provider.SessionAll()
}

// Set hash function for generating session id.
func (manager *Manager) SetHashFunc(hasfunc, hashkey string) {
	manager.config.SessionIDHashFunc = hasfunc
	manager.config.SessionIDHashKey = hashkey
}

// Set cookie with https.
func (manager *Manager) SetSecure(secure bool) {
	manager.config.Secure = secure
}

// generate session id with rand string, unix nano time, remote addr by hash function.
func (manager *Manager) sessionId(r *http.Request) (sid string) {
	bs := make([]byte, 32)
	if n, err := io.ReadFull(rand.Reader, bs); n != 32 || err != nil {
		bs = RandomCreateBytes(32)
	}
	sig := fmt.Sprintf("%s%d%s", r.RemoteAddr, time.Now().UnixNano(), bs)
	if manager.config.SessionIDHashFunc == "md5" {
		h := md5.New()
		h.Write([]byte(sig))
		sid = hex.EncodeToString(h.Sum(nil))
	} else if manager.config.SessionIDHashFunc == "sha1" {
		h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey))
		fmt.Fprintf(h, "%s", sig)
		sid = hex.EncodeToString(h.Sum(nil))
	} else {
		h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey))
		fmt.Fprintf(h, "%s", sig)
		sid = hex.EncodeToString(h.Sum(nil))
	}
	return
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/exoscale/egoscale"
	"github.com/spf13/cobra"
)

// firewallAddCmd represents the add command
var firewallAddCmd = &cobra.Command{
	Use:   "add <security group name | id>  [ssh | telnet | rdp | ...] (default preset rules)",
	Short: "Add rule to a security group",
}

func firewallAddRun(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		firewallAddCmd.Usage()
		return
	}

	securityGroup, err := getSecuGrpWithNameOrID(cs, args[0])
	if err != nil {
		log.Fatal(err)
	}

	desc, err := cmd.Flags().GetString("description")
	if err != nil {
		log.Fatal(err)
	}

	isIpv6, err := cmd.Flags().GetBool("ipv6")
	if err != nil {
		log.Fatal(err)
	}

	rule := &egoscale.AuthorizeSecurityGroupIngress{}

	for i := 1; true; i++ {

		if i >= len(args) {
			if len(args) != 1 {
				break
			}
		}

		if len(args) > 1 {
			rule, err = getDefaultRule(args[i], isIpv6)
			if err != nil {
				log.Fatal(err)
			}
		}

		rule.Description = desc
		rule.SecurityGroupID = securityGroup.ID

		isMyIP, err := cmd.Flags().GetBool("my-ip")
		if err != nil {
			log.Fatal(err)
		}

		ip := ""
		if isMyIP {
			cidr, err := getMyCIDR(isIpv6)
			if err != nil {
				log.Fatal(err)
			}
			ip = cidr.String()
		}

		if ip != "" {
			rule.CidrList = []string{ip}
		}

		protocol, err := cmd.Flags().GetString("protocol")
		if err != nil {
			log.Fatal(err)
		}

		if protocol != "" {
			rule.Protocol = strings.ToLower(protocol)
		}

		cidr, err := cmd.Flags().GetString("cidr")
		if err != nil {
			log.Fatal(err)
		}

		if cidr != "" {
			cidrs := getCommaflag(cidr)

			for _, c := range cidrs {
				rule.CidrList = append(rule.CidrList, c)
			}
		}

		sg, err := cmd.Flags().GetString("security-group")
		if err != nil {
			log.Fatal(err)
		}

		if sg != "" {
			sgs := getCommaflag(sg)

			userSecurityGroups, err := getSGs(cs, sgs)
			if err != nil {
				log.Fatal(err)
			}

			rule.UserSecurityGroupList = userSecurityGroups
		}

		icmptype, err := getUint8CustomFlag(cmd, "icmp-type")
		if err != nil {
			log.Fatal(err)
		}
		icmpcode, err := getUint8CustomFlag(cmd, "icmp-code")
		if err != nil {
			log.Fatal(err)
		}

		if icmptype.uint8 != nil {
			rule.IcmpType = *icmptype.uint8
		}

		if icmpcode.uint8 != nil {
			rule.IcmpCode = *icmpcode.uint8
		}

		isEgress, err := cmd.Flags().GetBool("engress")
		if err != nil {
			log.Fatal(err)
		}

		port, err := cmd.Flags().GetString("port")
		if err != nil {
			log.Fatal(err)
		}

		//Not best practis but waiting to find better solution
		if port != "" && (rule.Protocol == "tcp" || rule.Protocol == "udp") {

			ports := getCommaflag(port)
			portsRange, err := getPortsRange(ports)
			if err != nil {
				log.Fatal(err)
			}

			for _, portRange := range portsRange {

				rule.StartPort = portRange.start
				rule.EndPort = portRange.end
				if err := addRule(rule, isEgress); err != nil {
					log.Fatal(err)
				}
			}
		}
		//Not best practis but waiting to find better solution
		if port == "" || !(rule.Protocol == "tcp" || rule.Protocol == "udp") {
			if err := addRule(rule, isEgress); err != nil {
				log.Fatal(err)
			}
		}

		if len(args) == 1 {
			break
		}

	}

	firewallDetails(rule.SecurityGroupID)
}

type portRange struct {
	start uint16
	end   uint16
}

func getPortsRange(ports []string) ([]portRange, error) {
	portsRange := make([]portRange, len(ports))
	for i, p := range ports {
		pRange := strings.Split(p, "-")
		if len(pRange) > 2 || len(pRange) == 0 {
			return nil, fmt.Errorf("failed to get ports")
		}
		p1, err := strconv.ParseUint(pRange[0], 10, 16)
		if err != nil {
			return nil, err
		}
		portsRange[i].start = uint16(p1)
		portsRange[i].end = uint16(p1)
		if len(pRange) == 2 {
			p2, err := strconv.ParseUint(pRange[0], 10, 16)
			if err != nil {
				return nil, err
			}
			portsRange[i].end = uint16(p2)
		}
	}
	return portsRange, nil
}

func getSGs(cs *egoscale.Client, sgs []string) ([]egoscale.UserSecurityGroup, error) {

	sgRes := []egoscale.UserSecurityGroup{}

	for _, sg := range sgs {

		s, err := getSecuGrpWithNameOrID(cs, sg)
		if err != nil {
			return nil, err
		}
		sgRes = append(sgRes, egoscale.UserSecurityGroup{Group: s.Name, Account: s.Account})
	}
	return sgRes, nil
}

func getDefaultRule(ruleName string, isIpv6 bool) (*egoscale.AuthorizeSecurityGroupIngress, error) {

	icmpType := uint8(8)
	cidr := defaultCidr
	if isIpv6 {
		cidr = defaultCidr6
		icmpType = uint8(128)
	}

	ruleName = strings.ToLower(ruleName)
	if ruleName == "ping" {
		return &egoscale.AuthorizeSecurityGroupIngress{
			Protocol:    "icmp",
			CidrList:    []string{cidr},
			IcmpType:    icmpType,
			IcmpCode:    0,
			Description: "",
		}, nil
	}

	for d := Daytime; d <= Minecraft; d++ {
		if strings.ToLower(port.String(d)) == ruleName {
			return &egoscale.AuthorizeSecurityGroupIngress{
				Protocol:    "tcp",
				CidrList:    []string{cidr},
				StartPort:   uint16(d),
				EndPort:     uint16(d),
				Description: fmt.Sprintf(""),
			}, nil
		}
	}

	return nil, fmt.Errorf("default rule %q not found", ruleName)
}

func addRule(rule *egoscale.AuthorizeSecurityGroupIngress, isEgress bool) error {
	var err error
	if isEgress {
		_, err = cs.Request((*egoscale.AuthorizeSecurityGroupEgress)(rule))
	} else {
		_, err = cs.Request(rule)
	}

	if err != nil {
		return err
	}

	return nil
}

func init() {
	firewallAddCmd.Run = firewallAddRun

	firewallAddCmd.Flags().BoolP("ipv6", "6", false, "Set ipv6 on default rules or on --my-ip")
	firewallAddCmd.Flags().BoolP("my-ip", "", false, "Set CIDR for my ip")
	firewallAddCmd.Flags().BoolP("engress", "e", false, "By default rule is INGRESS (set --engress to have ENGRESS rule)")
	firewallAddCmd.Flags().StringP("protocol", "p", "", "Rule Protocol available [tcp, udp, icmp, icmpv6, ah, esp, gre]")
	firewallAddCmd.Flags().StringP("cidr", "c", "", "Rule Cidr [CIDR 0.0.0.0/0,::/0,...]")
	firewallAddCmd.Flags().StringP("security-group", "s", "", "Rule security group [name or id ex: sg1,sg2...]")
	firewallAddCmd.Flags().StringP("port", "P", "", "Rule port range [80-80,443,22-22]")

	//Flag for icmp
	icmpTypeVarP := new(uint8PtrValue)
	icmpCodeVarP := new(uint8PtrValue)

	firewallAddCmd.Flags().VarP(icmpTypeVarP, "icmp-type", "", "Set icmp type")
	firewallAddCmd.Flags().VarP(icmpCodeVarP, "icmp-code", "", "Set icmp type code")

	firewallAddCmd.Flags().StringP("description", "d", "", "Rule description")
	firewallCmd.AddCommand(firewallAddCmd)
}

type uint8PtrValue struct {
	*uint8
}

func (v *uint8PtrValue) Set(val string) error {
	r, err := strconv.ParseUint(val, 10, 8)
	if err != nil {
		return err
	}
	res := uint8(r)
	v.uint8 = &res
	return nil
}

func (v *uint8PtrValue) Type() string {
	return "uint8"
}

func (v *uint8PtrValue) String() string {

	if v.uint8 == nil {
		return "nil"
	}
	return strconv.FormatUint(uint64(*v.uint8), 10)
}

func getUint8CustomFlag(cmd *cobra.Command, name string) (uint8PtrValue, error) {
	it := cmd.Flags().Lookup(name)
	if it != nil {
		r := it.Value.(*uint8PtrValue)
		if r != nil {
			return *r, nil
		}
	}
	return uint8PtrValue{}, fmt.Errorf("Unable to get flag %s", name)
}
<commit_msg>Refacto https://github.com/exoscale/egoscale/commit/a7a0d0c3f96b23ebc91eaabae88e11f826477f4a<commit_after>package cmd

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/exoscale/egoscale"
	"github.com/spf13/cobra"
)

// firewallAddCmd represents the add command
var firewallAddCmd = &cobra.Command{
	Use:   "add <security group name | id>  [ssh | telnet | rdp | ...] (default preset rules)",
	Short: "Add rule to a security group",
}

func firewallAddRun(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		firewallAddCmd.Usage()
		return
	}

	securityGroup, err := getSecuGrpWithNameOrID(cs, args[0])
	if err != nil {
		log.Fatal(err)
	}

	desc, err := cmd.Flags().GetString("description")
	if err != nil {
		log.Fatal(err)
	}

	isIpv6, err := cmd.Flags().GetBool("ipv6")
	if err != nil {
		log.Fatal(err)
	}

	rule := &egoscale.AuthorizeSecurityGroupIngress{}

	for i := 1; true; i++ {

		if i >= len(args) && len(args) != 1 {
			break
		}

		if len(args) > 1 {
			rule, err = getDefaultRule(args[i], isIpv6)
			if err != nil {
				log.Fatal(err)
			}
		}

		rule.Description = desc
		rule.SecurityGroupID = securityGroup.ID

		isMyIP, err := cmd.Flags().GetBool("my-ip")
		if err != nil {
			log.Fatal(err)
		}

		ip := ""
		if isMyIP {
			cidr, err := getMyCIDR(isIpv6)
			if err != nil {
				log.Fatal(err)
			}
			ip = cidr.String()
		}

		if ip != "" {
			rule.CidrList = []string{ip}
		}

		protocol, err := cmd.Flags().GetString("protocol")
		if err != nil {
			log.Fatal(err)
		}

		if protocol != "" {
			rule.Protocol = strings.ToLower(protocol)
		}

		cidr, err := cmd.Flags().GetString("cidr")
		if err != nil {
			log.Fatal(err)
		}

		if cidr != "" {
			cidrs := getCommaflag(cidr)

			for _, c := range cidrs {
				rule.CidrList = append(rule.CidrList, c)
			}
		}

		sg, err := cmd.Flags().GetString("security-group")
		if err != nil {
			log.Fatal(err)
		}

		if sg != "" {
			sgs := getCommaflag(sg)

			userSecurityGroups, err := getSGs(cs, sgs)
			if err != nil {
				log.Fatal(err)
			}

			rule.UserSecurityGroupList = userSecurityGroups
		}

		icmptype, err := getUint8CustomFlag(cmd, "icmp-type")
		if err != nil {
			log.Fatal(err)
		}
		icmpcode, err := getUint8CustomFlag(cmd, "icmp-code")
		if err != nil {
			log.Fatal(err)
		}

		if icmptype.uint8 != nil {
			rule.IcmpType = *icmptype.uint8
		}

		if icmpcode.uint8 != nil {
			rule.IcmpCode = *icmpcode.uint8
		}

		isEgress, err := cmd.Flags().GetBool("engress")
		if err != nil {
			log.Fatal(err)
		}

		port, err := cmd.Flags().GetString("port")
		if err != nil {
			log.Fatal(err)
		}

		//Not best practis but waiting to find better solution
		if port != "" && (rule.Protocol == "tcp" || rule.Protocol == "udp") {

			ports := getCommaflag(port)
			portsRange, err := getPortsRange(ports)
			if err != nil {
				log.Fatal(err)
			}

			for _, portRange := range portsRange {

				rule.StartPort = portRange.start
				rule.EndPort = portRange.end
				if err := addRule(rule, isEgress); err != nil {
					log.Fatal(err)
				}
			}
		}
		//Not best practis but waiting to find better solution
		if port == "" || !(rule.Protocol == "tcp" || rule.Protocol == "udp") {
			if err := addRule(rule, isEgress); err != nil {
				log.Fatal(err)
			}
		}

		if len(args) == 1 {
			break
		}

	}

	firewallDetails(rule.SecurityGroupID)
}

type portRange struct {
	start uint16
	end   uint16
}

func getPortsRange(ports []string) ([]portRange, error) {
	portsRange := make([]portRange, len(ports))
	for i, p := range ports {
		pRange := strings.Split(p, "-")
		if len(pRange) > 2 || len(pRange) == 0 {
			return nil, fmt.Errorf("failed to get ports")
		}
		p1, err := strconv.ParseUint(pRange[0], 10, 16)
		if err != nil {
			return nil, err
		}
		portsRange[i].start = uint16(p1)
		portsRange[i].end = uint16(p1)
		if len(pRange) == 2 {
			p2, err := strconv.ParseUint(pRange[0], 10, 16)
			if err != nil {
				return nil, err
			}
			portsRange[i].end = uint16(p2)
		}
	}
	return portsRange, nil
}

func getSGs(cs *egoscale.Client, sgs []string) ([]egoscale.UserSecurityGroup, error) {

	sgRes := []egoscale.UserSecurityGroup{}

	for _, sg := range sgs {

		s, err := getSecuGrpWithNameOrID(cs, sg)
		if err != nil {
			return nil, err
		}
		sgRes = append(sgRes, egoscale.UserSecurityGroup{Group: s.Name, Account: s.Account})
	}
	return sgRes, nil
}

func getDefaultRule(ruleName string, isIpv6 bool) (*egoscale.AuthorizeSecurityGroupIngress, error) {

	icmpType := uint8(8)
	cidr := defaultCidr
	if isIpv6 {
		cidr = defaultCidr6
		icmpType = uint8(128)
	}

	ruleName = strings.ToLower(ruleName)
	if ruleName == "ping" {
		return &egoscale.AuthorizeSecurityGroupIngress{
			Protocol:    "icmp",
			CidrList:    []string{cidr},
			IcmpType:    icmpType,
			IcmpCode:    0,
			Description: "",
		}, nil
	}

	for d := Daytime; d <= Minecraft; d++ {
		if strings.ToLower(port.String(d)) == ruleName {
			return &egoscale.AuthorizeSecurityGroupIngress{
				Protocol:    "tcp",
				CidrList:    []string{cidr},
				StartPort:   uint16(d),
				EndPort:     uint16(d),
				Description: fmt.Sprintf(""),
			}, nil
		}
	}

	return nil, fmt.Errorf("default rule %q not found", ruleName)
}

func addRule(rule *egoscale.AuthorizeSecurityGroupIngress, isEgress bool) error {
	var err error
	if isEgress {
		_, err = cs.Request((*egoscale.AuthorizeSecurityGroupEgress)(rule))
	} else {
		_, err = cs.Request(rule)
	}

	if err != nil {
		return err
	}

	return nil
}

func init() {
	firewallAddCmd.Run = firewallAddRun

	firewallAddCmd.Flags().BoolP("ipv6", "6", false, "Set ipv6 on default rules or on --my-ip")
	firewallAddCmd.Flags().BoolP("my-ip", "", false, "Set CIDR for my ip")
	firewallAddCmd.Flags().BoolP("engress", "e", false, "By default rule is INGRESS (set --engress to have ENGRESS rule)")
	firewallAddCmd.Flags().StringP("protocol", "p", "", "Rule Protocol available [tcp, udp, icmp, icmpv6, ah, esp, gre]")
	firewallAddCmd.Flags().StringP("cidr", "c", "", "Rule Cidr [CIDR 0.0.0.0/0,::/0,...]")
	firewallAddCmd.Flags().StringP("security-group", "s", "", "Rule security group [name or id ex: sg1,sg2...]")
	firewallAddCmd.Flags().StringP("port", "P", "", "Rule port range [80-80,443,22-22]")

	//Flag for icmp
	icmpTypeVarP := new(uint8PtrValue)
	icmpCodeVarP := new(uint8PtrValue)

	firewallAddCmd.Flags().VarP(icmpTypeVarP, "icmp-type", "", "Set icmp type")
	firewallAddCmd.Flags().VarP(icmpCodeVarP, "icmp-code", "", "Set icmp type code")

	firewallAddCmd.Flags().StringP("description", "d", "", "Rule description")
	firewallCmd.AddCommand(firewallAddCmd)
}

type uint8PtrValue struct {
	*uint8
}

func (v *uint8PtrValue) Set(val string) error {
	r, err := strconv.ParseUint(val, 10, 8)
	if err != nil {
		return err
	}
	res := uint8(r)
	v.uint8 = &res
	return nil
}

func (v *uint8PtrValue) Type() string {
	return "uint8"
}

func (v *uint8PtrValue) String() string {

	if v.uint8 == nil {
		return "nil"
	}
	return strconv.FormatUint(uint64(*v.uint8), 10)
}

func getUint8CustomFlag(cmd *cobra.Command, name string) (uint8PtrValue, error) {
	it := cmd.Flags().Lookup(name)
	if it != nil {
		r := it.Value.(*uint8PtrValue)
		if r != nil {
			return *r, nil
		}
	}
	return uint8PtrValue{}, fmt.Errorf("Unable to get flag %s", name)
}
<|endoftext|>


<commit_before>package tape

import (
	"log"
	"net/http"
	"strings"

	"github.com/labstack/echo/v4"
)

// Exce exce
var Exce = new(Exception)

// Exception throw exception
type Exception struct{}

// OK throw exception if !ok
func (e *Exception) OK(ok bool, message interface{}) {
	if !ok {
		panic(message)
	}
}

// Err throw exception if err!=nil
func (e *Exception) Err(err error, message interface{}) {
	if err != nil {
		if message == "" {
			switch {
			case strings.HasPrefix(err.Error(), "Error 1046"):
				message = "查询表名错误"
			case strings.HasPrefix(err.Error(), "Error 1049"):
				message = "查询库名错误"
			case strings.HasPrefix(err.Error(), "Error 1054"):
				message = "查询列名错误"
			case strings.HasPrefix(err.Error(), "Error 1062"):
				message = "写入数据重复"
			case strings.HasPrefix(err.Error(), "Error 1064"):
				message = "查询语句错误"
			case strings.HasPrefix(err.Error(), "sql:"):
				message = "查询数据失败"
			case strings.HasPrefix(err.Error(), "code=400,message=Unmarshal type error"):
				message = "数据类型错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unavailable desc"):
				message = "连接服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unknown desc"):
				message = "调用服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unimplemented desc"):
				message = "解析服务错误"
			default:
				message = err.Error()
			}
		}
		log.Println(err.Error(), message)
		panic(message)
	}
}

// Catch throw exception if recover err
func (e *Exception) Catch(ctx echo.Context) func() {
	return func() {
		if r := recover(); r != nil {
			ctx.JSON(http.StatusOK, Hash{
				STATUS:  FAIL,
				MESSAGE: r,
			})
		}
	}
}
<commit_msg>remove debug code<commit_after>package tape

import (
	"net/http"
	"strings"

	"github.com/labstack/echo/v4"
)

// Exce exce
var Exce = new(Exception)

// Exception throw exception
type Exception struct{}

// OK throw exception if !ok
func (e *Exception) OK(ok bool, message interface{}) {
	if !ok {
		panic(message)
	}
}

// Err throw exception if err!=nil
func (e *Exception) Err(err error, message interface{}) {
	if err != nil {
		if message == "" {
			switch {
			case strings.HasPrefix(err.Error(), "Error 1046"):
				message = "查询表名错误"
			case strings.HasPrefix(err.Error(), "Error 1049"):
				message = "查询库名错误"
			case strings.HasPrefix(err.Error(), "Error 1054"):
				message = "查询列名错误"
			case strings.HasPrefix(err.Error(), "Error 1062"):
				message = "写入数据重复"
			case strings.HasPrefix(err.Error(), "Error 1064"):
				message = "查询语句错误"
			case strings.HasPrefix(err.Error(), "sql:"):
				message = "查询数据失败"
			case strings.HasPrefix(err.Error(), "code=400,message=Unmarshal type error"):
				message = "数据类型错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unavailable desc"):
				message = "连接服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unknown desc"):
				message = "调用服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unimplemented desc"):
				message = "解析服务错误"
			default:
				message = err.Error()
			}
		}
		panic(message)
	}
}

// Catch throw exception if recover err
func (e *Exception) Catch(ctx echo.Context) func() {
	return func() {
		if r := recover(); r != nil {
			ctx.JSON(http.StatusOK, Hash{
				STATUS:  FAIL,
				MESSAGE: r,
			})
		}
	}
}
<|endoftext|>


<commit_before>// The package mongofixtures enables to load quickly and easily data into mongo db.
package mongofixtures

import (
	"github.com/kylelemons/go-gypsy/yaml"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"regexp"
	"strconv"
)

// A session holds the mongo session (based on labix.org/v2/mgo).
type Session struct {
	MongoSession *mgo.Session
	DatabaseName string
	ObjectIds    map[string]bson.ObjectId
}

// Builds a new Session with the given host and database name.
func Begin(host string, databaseName string) (Session, error) {
	mongoSession, err := mgo.Dial(host)
	session := Session{MongoSession: mongoSession, DatabaseName: databaseName}
	session.ObjectIds = make(map[string]bson.ObjectId, 0)
	return session, err
}

// Removes the collection identified by collectionName.
func (l *Session) Clean(collectionName string) error {
	err := l.MongoSession.DB(l.DatabaseName).C(collectionName).DropCollection()

	if err != nil && err.Error() == "ns not found" {
		err = nil
	}

	return nil
}

/*
Adds a bson-marshalled version of each documents passed as an argument.
Usage example :
    session.Push("collection", Document{Title:"hello world"}, Document{Title:"Hi there!"})
*/
func (l *Session) Push(collectionName string, documents ...interface{}) error {
	var err error
	for _, document := range documents {
		err = l.MongoSession.DB(l.DatabaseName).C(collectionName).Insert(document)
	}
	return err
}

func (l *Session) ImportYamlFile(path string) {
	file, err := yaml.ReadFile(path)

	if err != nil {
		panic(err)
	}

	nodes := file.Root.(yaml.Map)

	for collectionName, collectionMap := range nodes {
		cMap := collectionMap.(yaml.Map)
		for _, data := range cMap {
			l.Push(collectionName, l.importNode(data))
		}
	}

}

func (l *Session) importNode(value interface{}) interface{} {

	var result interface{}

	switch value.(type) {
	case yaml.Map:
		result = l.importMap(value.(yaml.Map))
	case yaml.List:
		result = l.importList(value.(yaml.List))
	case yaml.Scalar:
		result = l.importScalar(value.(yaml.Scalar))
	}

	return result
}

func (l *Session) importMap(value yaml.Map) interface{} {
	m := make(map[string]interface{}, 0)
	for key, subvalue := range value {
		m[key] = l.importNode(subvalue)
	}

	return m
}

func (l *Session) importList(value yaml.List) interface{} {
	list := make([]interface{}, 0)
	for _, subvalue := range value {
		list = append(list, l.importNode(subvalue))
	}
	return list
}

func (l *Session) importScalar(value yaml.Scalar) interface{} {
	isHolder, _ := regexp.Match("^__(.*)__$", []byte(value))

	var result interface{}

	if isHolder {
		result = l.getObjectId(string(value))
	} else {

		resBool, isBool := strconv.ParseBool(string(value))
		resFloat, isFloat := strconv.ParseFloat(string(value), 32)
		resInt, isInt := strconv.ParseInt(string(value), 10, 32)

		if isInt == nil {
			return resInt
		}
		if isFloat == nil {
			return resFloat
		}
		if isBool == nil {
			return resBool
		}

		return value
	}

	return result
}

func (l *Session) ImportYamlString(yml string) {

}

func (l *Session) getObjectId(placeholder string) bson.ObjectId {
	value, exists := l.ObjectIds[placeholder]
	if !exists {
		value = bson.NewObjectId()
		l.ObjectIds[placeholder] = value
	}

	return value
}

// Ends a session. Should be called with defer right after Begin :
//  session := Begin("localhost", "mydatabase")
//  defer session.End()
func (l *Session) End() {
	l.MongoSession.Close()
}
<commit_msg>Fixing Clean. Now emptying collection instead of dropping it. That caused indexes loss.<commit_after>// The package mongofixtures enables to load quickly and easily data into mongo db.
package mongofixtures

import (
	"github.com/kylelemons/go-gypsy/yaml"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"regexp"
	"strconv"
)

// A session holds the mongo session (based on labix.org/v2/mgo).
type Session struct {
	MongoSession *mgo.Session
	DatabaseName string
	ObjectIds    map[string]bson.ObjectId
}

// Builds a new Session with the given host and database name.
func Begin(host string, databaseName string) (Session, error) {
	mongoSession, err := mgo.Dial(host)
	session := Session{MongoSession: mongoSession, DatabaseName: databaseName}
	session.ObjectIds = make(map[string]bson.ObjectId, 0)
	return session, err
}

// Removes the collection identified by collectionName.
func (l *Session) Clean(collectionName string) error {
	_, err := l.MongoSession.DB(l.DatabaseName).C(collectionName).RemoveAll(nil)

	if err != nil && err.Error() == "ns not found" {
		err = nil
	}

	return nil
}

/*
Adds a bson-marshalled version of each documents passed as an argument.
Usage example :
    session.Push("collection", Document{Title:"hello world"}, Document{Title:"Hi there!"})
*/
func (l *Session) Push(collectionName string, documents ...interface{}) error {
	var err error
	for _, document := range documents {
		err = l.MongoSession.DB(l.DatabaseName).C(collectionName).Insert(document)
	}
	return err
}

func (l *Session) ImportYamlFile(path string) {
	file, err := yaml.ReadFile(path)

	if err != nil {
		panic(err)
	}

	nodes := file.Root.(yaml.Map)

	for collectionName, collectionMap := range nodes {
		cMap := collectionMap.(yaml.Map)
		for _, data := range cMap {
			l.Push(collectionName, l.importNode(data))
		}
	}

}

func (l *Session) importNode(value interface{}) interface{} {

	var result interface{}

	switch value.(type) {
	case yaml.Map:
		result = l.importMap(value.(yaml.Map))
	case yaml.List:
		result = l.importList(value.(yaml.List))
	case yaml.Scalar:
		result = l.importScalar(value.(yaml.Scalar))
	}

	return result
}

func (l *Session) importMap(value yaml.Map) interface{} {
	m := make(map[string]interface{}, 0)
	for key, subvalue := range value {
		m[key] = l.importNode(subvalue)
	}

	return m
}

func (l *Session) importList(value yaml.List) interface{} {
	list := make([]interface{}, 0)
	for _, subvalue := range value {
		list = append(list, l.importNode(subvalue))
	}
	return list
}

func (l *Session) importScalar(value yaml.Scalar) interface{} {
	isHolder, _ := regexp.Match("^__(.*)__$", []byte(value))

	var result interface{}

	if isHolder {
		result = l.getObjectId(string(value))
	} else {

		resBool, isBool := strconv.ParseBool(string(value))
		resFloat, isFloat := strconv.ParseFloat(string(value), 32)
		resInt, isInt := strconv.ParseInt(string(value), 10, 32)

		if isInt == nil {
			return resInt
		}
		if isFloat == nil {
			return resFloat
		}
		if isBool == nil {
			return resBool
		}

		return value
	}

	return result
}

func (l *Session) ImportYamlString(yml string) {

}

func (l *Session) getObjectId(placeholder string) bson.ObjectId {
	value, exists := l.ObjectIds[placeholder]
	if !exists {
		value = bson.NewObjectId()
		l.ObjectIds[placeholder] = value
	}

	return value
}

// Ends a session. Should be called with defer right after Begin :
//  session := Begin("localhost", "mydatabase")
//  defer session.End()
func (l *Session) End() {
	l.MongoSession.Close()
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 (
	"flag"
	"fmt"

	"./serviceproc"
	exec "github.com/mesos/mesos-go/executor"
	mesos "github.com/mesos/mesos-go/mesosproto"
)

//tbd: the monitoring needs to be improved and should be monitoring the launched
// process pid in the system, and the launched process should not exit
// in case there is a problem with the executor and it exits
// this also brings in the need of init-executor which will load the info
//about the existing processes on this slave

var procMap map[string](*serviceproc.RedisProc)

type exampleExecutor struct {
	tasksLaunched int
}

func newExampleExecutor() *exampleExecutor {
	return &exampleExecutor{tasksLaunched: 0}
}

func (exec *exampleExecutor) Registered(driver exec.ExecutorDriver, execInfo *mesos.ExecutorInfo, fwinfo *mesos.FrameworkInfo, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("Registered Executor on slave ", slaveInfo.GetHostname())
}

func (exec *exampleExecutor) Reregistered(driver exec.ExecutorDriver, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("Re-registered Executor on slave ", slaveInfo.GetHostname())
}

func (exec *exampleExecutor) Disconnected(exec.ExecutorDriver) {
	fmt.Println("Executor disconnected.")
}

func (exec *exampleExecutor) LaunchTask(driver exec.ExecutorDriver, taskInfo *mesos.TaskInfo) {
	fmt.Println("Launching task", taskInfo.GetName(), "with command", taskInfo.Command.GetValue())

	runStatus := &mesos.TaskStatus{
		TaskId: taskInfo.GetTaskId(),
		State:  mesos.TaskState_TASK_RUNNING.Enum(),
	}
	_, err := driver.SendStatusUpdate(runStatus)
	if err != nil {
		fmt.Println("Got error", err)
	}

	exec.tasksLaunched++
	fmt.Println("Total tasks launched ", exec.tasksLaunched)

	// this is where one would perform the requested task
	fmt.Println("Starting Redis server on given port\n")

	//tbd: only the service instance id needs to be passed here; how to get it?
	//tbd: who gets you the port value?
	redisproc, uidStr := serviceproc.NewRedisProc("ServiceInstnsID", (6379 + exec.tasksLaunched))
	procMap[uidStr] = redisproc
	fmt.Println("spawning a new server with id:%s and proc:%v", uidStr, redisproc)
	monitor := serviceproc.NewProcMonitor(redisproc)

	//tbd: this needs to be tested by invoking multiple servers on the same executor
	//if the same executor is used for all launchtasks, we cannot block here
	//and thus will need a goroutine; (but then why does example put task finished status here)
	monitor.SpawnandMonitor()
	// finished the task (success or failure) if returned from the above

	fmt.Println("Finishing task", taskInfo.GetName())
	finStatus := &mesos.TaskStatus{
		TaskId: taskInfo.GetTaskId(),
		State:  mesos.TaskState_TASK_FINISHED.Enum(),
	}
	_, err = driver.SendStatusUpdate(finStatus)
	if err != nil {
		fmt.Println("Got error", err)
	}
	fmt.Println("Task finished", taskInfo.GetName())
}

func (exec *exampleExecutor) KillTask(exec.ExecutorDriver, *mesos.TaskID) {
	fmt.Println("Kill task")
}

func (exec *exampleExecutor) FrameworkMessage(driver exec.ExecutorDriver, msg string) {
	fmt.Println("Got framework message: ", msg)
}

func (exec *exampleExecutor) Shutdown(exec.ExecutorDriver) {
	fmt.Println("Shutting down the executor")
}

func (exec *exampleExecutor) Error(driver exec.ExecutorDriver, err string) {
	fmt.Println("Got error message:", err)
}

// -------------------------- func inits () ----------------- //
func init() {
	flag.Parse()
}

func main() {
	fmt.Println("Starting Example Executor (Go)")

	dconfig := exec.DriverConfig{
		Executor: newExampleExecutor(),
	}

	//maps which stores the proc pointer wrt UID
	procMap = make(map[string](*serviceproc.RedisProc))

	//tbd: after new, an init on the executor has to be called
	//which will read info about existing redis processes
	//also need to check how mesos handles executor errors

	driver, err := exec.NewMesosExecutorDriver(dconfig)

	if err != nil {
		fmt.Println("Unable to create a ExecutorDriver ", err.Error())
	}

	_, err = driver.Start()
	if err != nil {
		fmt.Println("Got error:", err)
		return
	}
	fmt.Println("Executor process has started and running.")
	_, err = driver.Join()
	if err != nil {
		fmt.Println("driver failed:", err)
	}
	fmt.Println("executor terminating")
}
<commit_msg>updated taskLaunch to return with goroutine in a background<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 (
	"flag"
	"fmt"

	"./serviceproc"
	exec "github.com/mesos/mesos-go/executor"
	mesos "github.com/mesos/mesos-go/mesosproto"
)

//tbd: the monitoring needs to be improved and should be monitoring the launched
// process pid in the system, and the launched process should not exit
// in case there is a problem with the executor and it exits
// this also brings in the need of init-executor which will load the info
//about the existing processes on this slave

var procMap map[string](*serviceproc.RedisProc)

type exampleExecutor struct {
	tasksLaunched int
}

func newExampleExecutor() *exampleExecutor {
	return &exampleExecutor{tasksLaunched: 0}
}

func (exec *exampleExecutor) Registered(driver exec.ExecutorDriver, execInfo *mesos.ExecutorInfo, fwinfo *mesos.FrameworkInfo, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("Registered Executor on slave ", slaveInfo.GetHostname())
}

func (exec *exampleExecutor) Reregistered(driver exec.ExecutorDriver, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("Re-registered Executor on slave ", slaveInfo.GetHostname())
}

func (exec *exampleExecutor) Disconnected(exec.ExecutorDriver) {
	fmt.Println("Executor disconnected.")
}

func (exec *exampleExecutor) LaunchTask(driver exec.ExecutorDriver, taskInfo *mesos.TaskInfo) {
	fmt.Println("Launching task", taskInfo.GetName(), "with command", taskInfo.Command.GetValue())

	// this is where one would perform the requested task
	fmt.Println("Starting Redis server on given port\n")

	//tbd: only the service instance id needs to be passed here; how to get it?
	//tbd: who gets you the port value?
	redisproc, uidStr := serviceproc.NewRedisProc("ServiceInstnsID", (6379 + exec.tasksLaunched))
	procMap[uidStr] = redisproc
	fmt.Println("spawning a new server with id:%s and proc:%v", uidStr, redisproc)
	monitor := serviceproc.NewProcMonitor(redisproc)

	//tbd: this needs to be tested by invoking multiple servers on the same executor
	//if the same executor is used for all launchtasks, we cannot block here
	//and thus will need a goroutine; (but then why does example put task finished status here)
	go func(monitor *serviceproc.ProcMonitor) {

		monitor.SpawnandMonitor()

	}(monitor)
	// finished the task (success or failure) if returned from the above

	runStatus := &mesos.TaskStatus{
		TaskId: taskInfo.GetTaskId(),
		State:  mesos.TaskState_TASK_RUNNING.Enum(),
	}
	_, err := driver.SendStatusUpdate(runStatus)
	if err != nil {
		fmt.Println("Got error", err)
	}

	exec.tasksLaunched++
	fmt.Println("Total tasks launched ", exec.tasksLaunched)

	fmt.Println("Finishing task", taskInfo.GetName())
	finStatus := &mesos.TaskStatus{
		TaskId: taskInfo.GetTaskId(),
		State:  mesos.TaskState_TASK_FINISHED.Enum(),
	}
	_, err = driver.SendStatusUpdate(finStatus)
	if err != nil {
		fmt.Println("Got error", err)
	}
	fmt.Println("Task finished", taskInfo.GetName())
}

func (exec *exampleExecutor) KillTask(exec.ExecutorDriver, *mesos.TaskID) {
	fmt.Println("Kill task")
}

func (exec *exampleExecutor) FrameworkMessage(driver exec.ExecutorDriver, msg string) {
	fmt.Println("Got framework message: ", msg)
}

func (exec *exampleExecutor) Shutdown(exec.ExecutorDriver) {
	fmt.Println("Shutting down the executor")
}

func (exec *exampleExecutor) Error(driver exec.ExecutorDriver, err string) {
	fmt.Println("Got error message:", err)
}

// -------------------------- func inits () ----------------- //
func init() {
	flag.Parse()
}

func main() {
	fmt.Println("Starting Example Executor (Go)")

	dconfig := exec.DriverConfig{
		Executor: newExampleExecutor(),
	}

	//maps which stores the proc pointer wrt UID
	procMap = make(map[string](*serviceproc.RedisProc))

	//tbd: after new, an init on the executor has to be called
	//which will read info about existing redis processes
	//also need to check how mesos handles executor errors

	driver, err := exec.NewMesosExecutorDriver(dconfig)

	if err != nil {
		fmt.Println("Unable to create a ExecutorDriver ", err.Error())
	}

	_, err = driver.Start()
	if err != nil {
		fmt.Println("Got error:", err)
		return
	}
	fmt.Println("Executor process has started and running.")
	_, err = driver.Join()
	if err != nil {
		fmt.Println("driver failed:", err)
	}
	fmt.Println("executor terminating")
}
<|endoftext|>


<commit_before>package main

// This file deals with executing user code and sending output messages.

import (
    "fmt"
    eval "github.com/sbinet/go-eval"
    repl "github.com/dwhitena/gophernotes/replpkg"
    "go/token"
)

// World holds the user namespace for the REPL.
var REPLSession *repl.Session
var World *eval.World
var fset *token.FileSet
// ExecCounter is incremented each time we run user code.
var ExecCounter int = 0

func SetupExecutionEnvironment() {

    REPLSession, err := repl.NewSession()
    if err != nil {
     panic(err)
    }

    fmt.Println(REPLSession)

    World = eval.NewWorld()
    fset = token.NewFileSet()
}

// RunCode runs the given user code, returning the expression value and/or an error.
func RunCode(text string) (val interface{}, err error) {
    var code eval.Code
    code, err = World.Compile(fset, text)
    if err != nil {
        return nil, err
    }
    val, err = code.Run()
    return
}

// OutputMsg holds the data for a pyout message.
type OutputMsg struct {
    Execcount int `json:"execution_count"`
    Data map[string]string `json:"data"`
    Metadata map[string]interface{} `json:"metadata"`
}

type ErrMsg struct {
    EName string `json:"ename"`
    EValue string `json:"evalue"`
    Traceback []string `json:"traceback"`
}

// HandleExecuteRequest runs code from an execute_request method, and sends the various
// reply messages.
func HandleExecuteRequest(receipt MsgReceipt) {
    reply := NewMsg("execute_reply", receipt.Msg)
    content := make(map[string]interface{})
    reqcontent := receipt.Msg.Content.(map[string]interface{})
    code := reqcontent["code"].(string)
    silent := reqcontent["silent"].(bool)
    if !silent {
        ExecCounter++
    }
    content["execution_count"] = ExecCounter
    //testerr := REPLSession.Eval(code)
    fmt.Println(testerr)
    val, err := RunCode(code)
    if err == nil {
        content["status"] = "ok"
        content["payload"] = make([]map[string]interface{}, 0)
        content["user_variables"] = make(map[string]string)
        content["user_expressions"] = make(map[string]string)
        if (val != nil) && !silent {
            var out_content OutputMsg
            out := NewMsg("pyout", receipt.Msg)
            out_content.Execcount = ExecCounter
            out_content.Data = make(map[string]string)
            out_content.Data["text/plain"] = fmt.Sprint(val)
            out_content.Metadata = make(map[string]interface{})
            out.Content = out_content
            receipt.SendResponse(receipt.Sockets.IOPub_socket, out)
        }
    } else {
        content["status"] = "error"
        content["ename"] = "ERROR"
        content["evalue"] = err.Error()
        content["traceback"] = []string{err.Error()}
        errormsg := NewMsg("pyerr", receipt.Msg)
        errormsg.Content = ErrMsg{"Error", err.Error(), []string{err.Error()}}
        receipt.SendResponse(receipt.Sockets.IOPub_socket, errormsg)
    }
    reply.Content = content
    receipt.SendResponse(receipt.Sockets.Shell_socket, reply)
    idle := NewMsg("status", receipt.Msg)
    idle.Content = KernelStatus{"idle"}
    receipt.SendResponse(receipt.Sockets.IOPub_socket, idle)
}<commit_msg>debugging repl<commit_after>package main

// This file deals with executing user code and sending output messages.

import (
    "fmt"
    eval "github.com/sbinet/go-eval"
    repl "github.com/dwhitena/gophernotes/replpkg"
    "go/token"
)

// World holds the user namespace for the REPL.
var REPLSession *repl.Session
var World *eval.World
var fset *token.FileSet
// ExecCounter is incremented each time we run user code.
var ExecCounter int = 0

func SetupExecutionEnvironment() {

    REPLSession, err := repl.NewSession()
    if err != nil {
     panic(err)
    }

    fmt.Println(REPLSession)

    World = eval.NewWorld()
    fset = token.NewFileSet()
}

// RunCode runs the given user code, returning the expression value and/or an error.
func RunCode(text string) (val interface{}, err error) {
    var code eval.Code
    code, err = World.Compile(fset, text)
    if err != nil {
        return nil, err
    }
    val, err = code.Run()
    return
}

// OutputMsg holds the data for a pyout message.
type OutputMsg struct {
    Execcount int `json:"execution_count"`
    Data map[string]string `json:"data"`
    Metadata map[string]interface{} `json:"metadata"`
}

type ErrMsg struct {
    EName string `json:"ename"`
    EValue string `json:"evalue"`
    Traceback []string `json:"traceback"`
}

// HandleExecuteRequest runs code from an execute_request method, and sends the various
// reply messages.
func HandleExecuteRequest(receipt MsgReceipt) {
    reply := NewMsg("execute_reply", receipt.Msg)
    content := make(map[string]interface{})
    reqcontent := receipt.Msg.Content.(map[string]interface{})
    code := reqcontent["code"].(string)
    silent := reqcontent["silent"].(bool)
    if !silent {
        ExecCounter++
    }
    content["execution_count"] = ExecCounter
    //testerr := REPLSession.Eval(code)
    fmt.Println(code)
    val, err := RunCode(code)
    if err == nil {
        content["status"] = "ok"
        content["payload"] = make([]map[string]interface{}, 0)
        content["user_variables"] = make(map[string]string)
        content["user_expressions"] = make(map[string]string)
        if (val != nil) && !silent {
            var out_content OutputMsg
            out := NewMsg("pyout", receipt.Msg)
            out_content.Execcount = ExecCounter
            out_content.Data = make(map[string]string)
            out_content.Data["text/plain"] = fmt.Sprint(val)
            out_content.Metadata = make(map[string]interface{})
            out.Content = out_content
            receipt.SendResponse(receipt.Sockets.IOPub_socket, out)
        }
    } else {
        content["status"] = "error"
        content["ename"] = "ERROR"
        content["evalue"] = err.Error()
        content["traceback"] = []string{err.Error()}
        errormsg := NewMsg("pyerr", receipt.Msg)
        errormsg.Content = ErrMsg{"Error", err.Error(), []string{err.Error()}}
        receipt.SendResponse(receipt.Sockets.IOPub_socket, errormsg)
    }
    reply.Content = content
    receipt.SendResponse(receipt.Sockets.Shell_socket, reply)
    idle := NewMsg("status", receipt.Msg)
    idle.Content = KernelStatus{"idle"}
    receipt.SendResponse(receipt.Sockets.IOPub_socket, idle)
}<|endoftext|>