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

package main

import (
	"fmt";
	"go/ast";
	"go/printer";
	"os";
	"strings";
)

func creat(name string) *os.File {
	f, err := os.Open(name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0666);
	if err != nil {
		fatal("%s", err);
	}
	return f;
}

// writeOutput creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Prog) writeOutput(srcfile string) {
	pkgroot := os.Getenv("GOROOT") + "/pkg/" + os.Getenv("GOOS") + "_" + os.Getenv("GOARCH");

	base := srcfile;
	if strings.HasSuffix(base, ".go") {
		base = base[0 : len(base)-3];
	}
	fgo1 := creat(base + ".cgo1.go");
	fgo2 := creat(base + ".cgo2.go");
	fc := creat(base + ".cgo3.c");
	fgcc := creat(base + ".cgo4.c");

	// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n");
	fmt.Fprintf(fgo1, "//line %s:1\n", srcfile);
	printer.Fprint(fgo1, p.AST, 0, 8, nil);

	// Write second Go output: definitions of _C_xxx.
	// In a separate file so that the import of "unsafe" does not
	// pollute the original file.
	fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n");
	fmt.Fprintf(fgo2, "package %s\n\n", p.Package);
	fmt.Fprintf(fgo2, "import \"unsafe\"\n\n");
	fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n");

	for name, def := range p.Typedef {
		fmt.Fprintf(fgo2, "type %s ", name);
		printer.Fprint(fgo2, def, 0, 8, nil);
		fmt.Fprintf(fgo2, "\n");
	}
	fmt.Fprintf(fgo2, "type _C_void [0]byte\n");

	// While we process the vars and funcs, also write 6c and gcc output.
	// Gcc output starts with the preamble.
	fmt.Fprintf(fgcc, "%s\n", p.Preamble);
	fmt.Fprintf(fgcc, "%s\n", gccProlog);

	fmt.Fprintf(fc, cProlog, pkgroot, pkgroot, pkgroot, pkgroot, p.Package, p.Package);

	for name, def := range p.Vardef {
		fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s/%s_%s.so\"\n", p.Package, name, name, pkgroot, p.PackagePath, base);
		fmt.Fprintf(fgo2, "var _C_%s ", name);
		printer.Fprint(fgo2, &ast.StarExpr{X: def.Go}, 0, 8, nil);
		fmt.Fprintf(fgo2, "\n");
	}
	fmt.Fprintf(fc, "\n");

	for name, def := range p.Funcdef {
		// Go func declaration.
		d := &ast.FuncDecl{
			Name: &ast.Ident{Value: "_C_"+name},
			Type: def.Go,
		};
		printer.Fprint(fgo2, d, 0, 8, nil);
		fmt.Fprintf(fgo2, "\n");

		if name == "CString" || name == "GoString" {
			// The builtins are already defined in the C prolog.
			continue;
		}

		// Construct a gcc struct matching the 6c argument frame.
		// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
		// These assumptions are checked by the gccProlog.
		// Also assumes that 6c convention is to word-align the
		// input and output parameters.
		structType := "struct {\n";
		off := int64(0);
		npad := 0;
		for i, t := range def.Params {
			if off % t.Align != 0 {
				pad := t.Align - off % t.Align;
				structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
				off += pad;
				npad++;
			}
			structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i);
			off += t.Size;
		}
		if off % p.PtrSize != 0 {
			pad := p.PtrSize - off % p.PtrSize;
			structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
			off += pad;
			npad++;
		}
		if t := def.Result; t != nil {
			if off % t.Align != 0 {
				pad := t.Align - off % t.Align;
				structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
				off += pad;
				npad++;
			}
			structType += fmt.Sprintf("\t\t%s r;\n", t.C);
			off += t.Size;
		}
		if off % p.PtrSize != 0 {
			pad := p.PtrSize - off % p.PtrSize;
			structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
			off += pad;
			npad++;
		}
		if len(def.Params) == 0 && def.Result == nil {
			structType += "\t\tchar unused;\n";	// avoid empty struct
			off++;
		}
		structType += "\t}";
		argSize := off;

		// C wrapper calls into gcc, passing a pointer to the argument frame.
		// Also emit #pragma to get a pointer to the gcc wrapper.
		fmt.Fprintf(fc, "#pragma dynld _cgo_%s _cgo_%s \"%s/%s_%s.so\"\n", name, name, pkgroot, p.PackagePath, base);
		fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name);
		fmt.Fprintf(fc, "\n");
		fmt.Fprintf(fc, "void\n");
		fmt.Fprintf(fc, "%s·_C_%s(struct{uint8 x[%d];}p)\n", p.Package, name, argSize);
		fmt.Fprintf(fc, "{\n");
		fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name);
		fmt.Fprintf(fc, "}\n");
		fmt.Fprintf(fc, "\n");

		// Gcc wrapper unpacks the C argument struct
		// and calls the actual C function.
		fmt.Fprintf(fgcc, "void\n");
		fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name);
		fmt.Fprintf(fgcc, "{\n");
		fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType);
		fmt.Fprintf(fgcc, "\t");
		if def.Result != nil {
			fmt.Fprintf(fgcc, "a->r = ");
		}
		fmt.Fprintf(fgcc, "%s(", name);
		for i := range def.Params {
			if i > 0 {
				fmt.Fprintf(fgcc, ", ");
			}
			fmt.Fprintf(fgcc, "a->p%d", i);
		}
		fmt.Fprintf(fgcc, ");\n");
		fmt.Fprintf(fgcc, "}\n");
		fmt.Fprintf(fgcc, "\n");
	}

	fgo1.Close();
	fgo2.Close();
	fc.Close();
	fgcc.Close();
}

const gccProlog = `
// Usual nonsense: if x and y are not equal, the type will be invalid
// (have a negative array count) and an inscrutable error will come
// out of the compiler and hopefully mention "name".
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];

// Check at compile time that the sizes we use match our expectations.
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)

__cgo_size_assert(char, 1)
__cgo_size_assert(short, 2)
__cgo_size_assert(int, 4)
typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
`

const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
_GoString_ GoString(char *p);
char *CString(_GoString_);
`

const cProlog = `
#include "runtime.h"
#include "cgocall.h"

#pragma dynld initcgo initcgo "%s/libcgo.so"
#pragma dynld libcgo_thread_start libcgo_thread_start "%s/libcgo.so"
#pragma dynld _cgo_malloc _cgo_malloc "%s/libcgo.so"
#pragma dynld _cgo_free free "%s/libcgo.so"

void
%s·_C_GoString(int8 *p, String s)
{
	s = gostring((byte*)p);
	FLUSH(&s);
}

void
%s·_C_CString(String s, int8 *p)
{
	p = cmalloc(s.len+1);
	mcpy((byte*)p, s.str, s.len);
	p[s.len] = 0;
	FLUSH(&p);
}
`
<commit_msg>fix build<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt";
	"go/ast";
	"go/printer";
	"os";
	"strings";
)

func creat(name string) *os.File {
	f, err := os.Open(name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0666);
	if err != nil {
		fatal("%s", err);
	}
	return f;
}

// writeOutput creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Prog) writeOutput(srcfile string) {
	pkgroot := os.Getenv("GOROOT") + "/pkg/" + os.Getenv("GOOS") + "_" + os.Getenv("GOARCH");

	base := srcfile;
	if strings.HasSuffix(base, ".go") {
		base = base[0 : len(base)-3];
	}
	fgo1 := creat(base + ".cgo1.go");
	fgo2 := creat(base + ".cgo2.go");
	fc := creat(base + ".cgo3.c");
	fgcc := creat(base + ".cgo4.c");

	// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n");
	fmt.Fprintf(fgo1, "//line %s:1\n", srcfile);
	printer.Fprint(fgo1, p.AST);

	// Write second Go output: definitions of _C_xxx.
	// In a separate file so that the import of "unsafe" does not
	// pollute the original file.
	fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n");
	fmt.Fprintf(fgo2, "package %s\n\n", p.Package);
	fmt.Fprintf(fgo2, "import \"unsafe\"\n\n");
	fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n");

	for name, def := range p.Typedef {
		fmt.Fprintf(fgo2, "type %s ", name);
		printer.Fprint(fgo2, def);
		fmt.Fprintf(fgo2, "\n");
	}
	fmt.Fprintf(fgo2, "type _C_void [0]byte\n");

	// While we process the vars and funcs, also write 6c and gcc output.
	// Gcc output starts with the preamble.
	fmt.Fprintf(fgcc, "%s\n", p.Preamble);
	fmt.Fprintf(fgcc, "%s\n", gccProlog);

	fmt.Fprintf(fc, cProlog, pkgroot, pkgroot, pkgroot, pkgroot, p.Package, p.Package);

	for name, def := range p.Vardef {
		fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s/%s_%s.so\"\n", p.Package, name, name, pkgroot, p.PackagePath, base);
		fmt.Fprintf(fgo2, "var _C_%s ", name);
		printer.Fprint(fgo2, &ast.StarExpr{X: def.Go});
		fmt.Fprintf(fgo2, "\n");
	}
	fmt.Fprintf(fc, "\n");

	for name, def := range p.Funcdef {
		// Go func declaration.
		d := &ast.FuncDecl{
			Name: &ast.Ident{Value: "_C_"+name},
			Type: def.Go,
		};
		printer.Fprint(fgo2, d);
		fmt.Fprintf(fgo2, "\n");

		if name == "CString" || name == "GoString" {
			// The builtins are already defined in the C prolog.
			continue;
		}

		// Construct a gcc struct matching the 6c argument frame.
		// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
		// These assumptions are checked by the gccProlog.
		// Also assumes that 6c convention is to word-align the
		// input and output parameters.
		structType := "struct {\n";
		off := int64(0);
		npad := 0;
		for i, t := range def.Params {
			if off % t.Align != 0 {
				pad := t.Align - off % t.Align;
				structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
				off += pad;
				npad++;
			}
			structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i);
			off += t.Size;
		}
		if off % p.PtrSize != 0 {
			pad := p.PtrSize - off % p.PtrSize;
			structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
			off += pad;
			npad++;
		}
		if t := def.Result; t != nil {
			if off % t.Align != 0 {
				pad := t.Align - off % t.Align;
				structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
				off += pad;
				npad++;
			}
			structType += fmt.Sprintf("\t\t%s r;\n", t.C);
			off += t.Size;
		}
		if off % p.PtrSize != 0 {
			pad := p.PtrSize - off % p.PtrSize;
			structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
			off += pad;
			npad++;
		}
		if len(def.Params) == 0 && def.Result == nil {
			structType += "\t\tchar unused;\n";	// avoid empty struct
			off++;
		}
		structType += "\t}";
		argSize := off;

		// C wrapper calls into gcc, passing a pointer to the argument frame.
		// Also emit #pragma to get a pointer to the gcc wrapper.
		fmt.Fprintf(fc, "#pragma dynld _cgo_%s _cgo_%s \"%s/%s_%s.so\"\n", name, name, pkgroot, p.PackagePath, base);
		fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name);
		fmt.Fprintf(fc, "\n");
		fmt.Fprintf(fc, "void\n");
		fmt.Fprintf(fc, "%s·_C_%s(struct{uint8 x[%d];}p)\n", p.Package, name, argSize);
		fmt.Fprintf(fc, "{\n");
		fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name);
		fmt.Fprintf(fc, "}\n");
		fmt.Fprintf(fc, "\n");

		// Gcc wrapper unpacks the C argument struct
		// and calls the actual C function.
		fmt.Fprintf(fgcc, "void\n");
		fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name);
		fmt.Fprintf(fgcc, "{\n");
		fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType);
		fmt.Fprintf(fgcc, "\t");
		if def.Result != nil {
			fmt.Fprintf(fgcc, "a->r = ");
		}
		fmt.Fprintf(fgcc, "%s(", name);
		for i := range def.Params {
			if i > 0 {
				fmt.Fprintf(fgcc, ", ");
			}
			fmt.Fprintf(fgcc, "a->p%d", i);
		}
		fmt.Fprintf(fgcc, ");\n");
		fmt.Fprintf(fgcc, "}\n");
		fmt.Fprintf(fgcc, "\n");
	}

	fgo1.Close();
	fgo2.Close();
	fc.Close();
	fgcc.Close();
}

const gccProlog = `
// Usual nonsense: if x and y are not equal, the type will be invalid
// (have a negative array count) and an inscrutable error will come
// out of the compiler and hopefully mention "name".
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];

// Check at compile time that the sizes we use match our expectations.
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)

__cgo_size_assert(char, 1)
__cgo_size_assert(short, 2)
__cgo_size_assert(int, 4)
typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
`

const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
_GoString_ GoString(char *p);
char *CString(_GoString_);
`

const cProlog = `
#include "runtime.h"
#include "cgocall.h"

#pragma dynld initcgo initcgo "%s/libcgo.so"
#pragma dynld libcgo_thread_start libcgo_thread_start "%s/libcgo.so"
#pragma dynld _cgo_malloc _cgo_malloc "%s/libcgo.so"
#pragma dynld _cgo_free free "%s/libcgo.so"

void
%s·_C_GoString(int8 *p, String s)
{
	s = gostring((byte*)p);
	FLUSH(&s);
}

void
%s·_C_CString(String s, int8 *p)
{
	p = cmalloc(s.len+1);
	mcpy((byte*)p, s.str, s.len);
	p[s.len] = 0;
	FLUSH(&p);
}
`
<|endoftext|>


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

package config

import (
	"encoding/json"
)

type Unit struct {
	Name     UnitName     `json:"name,omitempty"     yaml:"name"`
	Enable   bool         `json:"enable,omitempty"   yaml:"enable"`
	Mask     bool         `json:"mask,omitempty"     yaml:"mask"`
	Contents string       `json:"contents,omitempty" yaml:"contents"`
	DropIns  []UnitDropIn `json:"dropIns,omitempty"  yaml:"dropIns"`
}

type UnitDropIn struct {
	Name     UnitName `json:"name,omitempty"     yaml:"name"`
	Contents string   `json:"contents,omitempty" yaml:"contents"`
}

type UnitName string

func (n *UnitName) UnmarshalYAML(unmarshal func(interface{}) error) error {
	return n.unmarshal(unmarshal)
}

func (n *UnitName) UnmarshalJSON(data []byte) error {
	return n.unmarshal(func(tn interface{}) error {
		return json.Unmarshal(data, tn)
	})
}

type unitName UnitName

func (n *UnitName) unmarshal(unmarshal func(interface{}) error) error {
	tn := unitName(*n)
	if err := unmarshal(&tn); err != nil {
		return err
	}
	*n = UnitName(tn)
	return n.assertValid()
}

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

package config

import (
	"encoding/json"
)

type Unit struct {
	Name     UnitName     `json:"name,omitempty"     yaml:"name"`
	Enable   bool         `json:"enable,omitempty"   yaml:"enable"`
	Mask     bool         `json:"mask,omitempty"     yaml:"mask"`
	Contents string       `json:"contents,omitempty" yaml:"contents"`
	DropIns  []UnitDropIn `json:"dropins,omitempty"  yaml:"dropins"`
}

type UnitDropIn struct {
	Name     UnitName `json:"name,omitempty"     yaml:"name"`
	Contents string   `json:"contents,omitempty" yaml:"contents"`
}

type UnitName string

func (n *UnitName) UnmarshalYAML(unmarshal func(interface{}) error) error {
	return n.unmarshal(unmarshal)
}

func (n *UnitName) UnmarshalJSON(data []byte) error {
	return n.unmarshal(func(tn interface{}) error {
		return json.Unmarshal(data, tn)
	})
}

type unitName UnitName

func (n *UnitName) unmarshal(unmarshal func(interface{}) error) error {
	tn := unitName(*n)
	if err := unmarshal(&tn); err != nil {
		return err
	}
	*n = UnitName(tn)
	return n.assertValid()
}

func (n UnitName) assertValid() error {
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"github.com/vansante/go-event-emitter"
	"gitlab.transip.us/swiltink/go-MusicBot/player"
	"gitlab.transip.us/swiltink/go-MusicBot/songplayer"
	"io/ioutil"
	"sync"
	"time"
)

const (
	writeWait      = 10 * time.Second
	pongWait       = 60 * time.Second
	pingPeriod     = (pongWait * 9) / 10
	maxMessageSize = 128
)

type ControlWebsocket struct {
	ws        *websocket.Conn
	readOnly  bool
	hasClosed bool
	player    player.MusicPlayer
	capturer  *eventemitter.Capturer
	writeLock sync.Mutex
}

func NewControlWebsocket(ws *websocket.Conn, readOnly bool, player player.MusicPlayer) (cws *ControlWebsocket) {
	cws = &ControlWebsocket{
		ws:       ws,
		readOnly: readOnly,
		player:   player,
	}
	return
}

func (cws *ControlWebsocket) Start() {
	cws.capturer = cws.player.AddCapturer(cws.onEvent)

	go cws.socketWriter()
	cws.socketReader()
}

func (cws *ControlWebsocket) onEvent(event string, args ...interface{}) {
	var apiArgs []interface{}
	// Loop through the arguments and if its a known type, translate it to the appropiate API type.
	for i := range args {
		apiArgs[i] = args[i]
		songs, ok := apiArgs[i].([]songplayer.Playable)
		if ok {
			apiArgs[i] = getAPISongs(songs)
			continue
		}
		song, ok := apiArgs[i].(songplayer.Playable)
		if ok {
			apiArgs[i] = getAPISong(song, song.GetDuration())
			continue
		}
		dur, ok := apiArgs[i].(time.Duration)
		if ok {
			apiArgs[i] = int(dur.Seconds())
			continue
		}
	}
	evt := Event{
		Event:     event,
		Arguments: apiArgs,
	}
	cws.write(evt)
}

func (cws *ControlWebsocket) socketWriter() {
	ticker := time.NewTicker(pingPeriod)

	// Make sure we stop the ticker when done
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			cws.writeLock.Lock()
			cws.ws.SetWriteDeadline(time.Now().Add(writeWait))
			err := cws.ws.WriteMessage(websocket.PingMessage, []byte{})
			cws.writeLock.Unlock()
			if err != nil {
				break
			}
		}
	}
	cws.closeConnection()
}

func (cws *ControlWebsocket) socketReader() {
	cws.ws.SetReadLimit(maxMessageSize)
	cws.ws.SetReadDeadline(time.Now().Add(pongWait))
	cws.ws.SetPongHandler(func(string) error {
		cws.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// If the application is not otherwise interested in messages from the peer,
	// then the application should start a goroutine to read and discard messages from the peer
	// (From the documentation)
	for {
		if tp, reader, err := cws.ws.NextReader(); err != nil {
			if cws.readOnly {
				// Ignore everything :)
				break
			}
			if tp != websocket.TextMessage {
				break
			}

			buf, err := ioutil.ReadAll(reader)
			if err != nil {
				cws.write("Error: " + err.Error())
				return
			}
			cmd := &Command{}
			err = json.Unmarshal(buf, cmd)
			if err != nil {
				cws.write("Error: " + err.Error())
				return
			}
			cws.executeCommand(cmd)
			break
		}
	}
	cws.closeConnection()
}

func (cws *ControlWebsocket) executeCommand(cmd *Command) {
	switch cmd.Command {
	case "add":
		if len(cmd.Arguments) < 1 {
			err := errors.New("Missing URL argument")
			cws.write(getCommandResponse(cmd, err))
			return
		}
		_, err := cws.player.AddSongs(cmd.Arguments[0])
		cws.write(getCommandResponse(cmd, err))
	case "open":
		if len(cmd.Arguments) < 1 {
			err := errors.New("Missing URL argument")
			cws.write(getCommandResponse(cmd, err))
			return
		}
		_, err := cws.player.InsertSongs(cmd.Arguments[0], 0)
		cws.write(getCommandResponse(cmd, err))
	case "play":
		_, err := cws.player.Play()
		cws.write(getCommandResponse(cmd, err))
	case "pause":
		err := cws.player.Pause()
		cws.write(getCommandResponse(cmd, err))
	case "status":
		song, remaining := cws.player.GetCurrentSong()
		resp := getCommandResponse(cmd, nil)
		resp.Status = &Status{
			Status:  cws.player.GetStatus(),
			Current: getAPISong(song, remaining),
			List:    getAPISongs(cws.player.GetQueuedSongs()),
		}
		cws.write(resp)
	case "next":
		_, err := cws.player.Next()
		cws.write(getCommandResponse(cmd, err))
	case "stop":
		err := cws.player.Stop()
		cws.write(getCommandResponse(cmd, err))
	case "empty-list":
		cws.player.EmptyQueue()
		cws.write(getCommandResponse(cmd, nil))
	case "shuffle-list":
		cws.player.ShuffleQueue()
		cws.write(getCommandResponse(cmd, nil))
	}
}

func (cws *ControlWebsocket) closeConnection() {
	// Use the write lock to ensure this function is _really_ called once.
	cws.writeLock.Lock()
	defer cws.writeLock.Unlock()

	if cws.hasClosed {
		return
	}
	cws.hasClosed = true

	// Close websocket
	cws.ws.Close()

	// Remove our event capturer
	cws.player.RemoveCapturer(cws.capturer)
}

func (cws *ControlWebsocket) write(data interface{}) {
	// Applications are responsible for ensuring that no more than one goroutine calls the write methods
	// (From the docs)
	cws.writeLock.Lock()
	cws.ws.SetWriteDeadline(time.Now().Add(writeWait))
	cws.ws.WriteJSON(data)
	cws.writeLock.Unlock()
}
<commit_msg>initialize slice properly<commit_after>package api

import (
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"github.com/vansante/go-event-emitter"
	"gitlab.transip.us/swiltink/go-MusicBot/player"
	"gitlab.transip.us/swiltink/go-MusicBot/songplayer"
	"io/ioutil"
	"sync"
	"time"
)

const (
	writeWait      = 10 * time.Second
	pongWait       = 60 * time.Second
	pingPeriod     = (pongWait * 9) / 10
	maxMessageSize = 128
)

type ControlWebsocket struct {
	ws        *websocket.Conn
	readOnly  bool
	hasClosed bool
	player    player.MusicPlayer
	capturer  *eventemitter.Capturer
	writeLock sync.Mutex
}

func NewControlWebsocket(ws *websocket.Conn, readOnly bool, player player.MusicPlayer) (cws *ControlWebsocket) {
	cws = &ControlWebsocket{
		ws:       ws,
		readOnly: readOnly,
		player:   player,
	}
	return
}

func (cws *ControlWebsocket) Start() {
	cws.capturer = cws.player.AddCapturer(cws.onEvent)

	go cws.socketWriter()
	cws.socketReader()
}

func (cws *ControlWebsocket) onEvent(event string, args ...interface{}) {
	apiArgs := make([]interface{}, len(args))
	// Loop through the arguments and if its a known type, translate it to the appropiate API type.
	for i := range args {
		apiArgs[i] = args[i]
		songs, ok := apiArgs[i].([]songplayer.Playable)
		if ok {
			apiArgs[i] = getAPISongs(songs)
			continue
		}
		song, ok := apiArgs[i].(songplayer.Playable)
		if ok {
			apiArgs[i] = getAPISong(song, song.GetDuration())
			continue
		}
		dur, ok := apiArgs[i].(time.Duration)
		if ok {
			apiArgs[i] = int(dur.Seconds())
			continue
		}
	}
	evt := Event{
		Event:     event,
		Arguments: apiArgs,
	}
	cws.write(evt)
}

func (cws *ControlWebsocket) socketWriter() {
	ticker := time.NewTicker(pingPeriod)

	// Make sure we stop the ticker when done
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			cws.writeLock.Lock()
			cws.ws.SetWriteDeadline(time.Now().Add(writeWait))
			err := cws.ws.WriteMessage(websocket.PingMessage, []byte{})
			cws.writeLock.Unlock()
			if err != nil {
				break
			}
		}
	}
	cws.closeConnection()
}

func (cws *ControlWebsocket) socketReader() {
	cws.ws.SetReadLimit(maxMessageSize)
	cws.ws.SetReadDeadline(time.Now().Add(pongWait))
	cws.ws.SetPongHandler(func(string) error {
		cws.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// If the application is not otherwise interested in messages from the peer,
	// then the application should start a goroutine to read and discard messages from the peer
	// (From the documentation)
	for {
		if tp, reader, err := cws.ws.NextReader(); err != nil {
			if cws.readOnly {
				// Ignore everything :)
				break
			}
			if tp != websocket.TextMessage {
				break
			}

			buf, err := ioutil.ReadAll(reader)
			if err != nil {
				cws.write("Error: " + err.Error())
				return
			}
			cmd := &Command{}
			err = json.Unmarshal(buf, cmd)
			if err != nil {
				cws.write("Error: " + err.Error())
				return
			}
			cws.executeCommand(cmd)
			break
		}
	}
	cws.closeConnection()
}

func (cws *ControlWebsocket) executeCommand(cmd *Command) {
	switch cmd.Command {
	case "add":
		if len(cmd.Arguments) < 1 {
			err := errors.New("Missing URL argument")
			cws.write(getCommandResponse(cmd, err))
			return
		}
		_, err := cws.player.AddSongs(cmd.Arguments[0])
		cws.write(getCommandResponse(cmd, err))
	case "open":
		if len(cmd.Arguments) < 1 {
			err := errors.New("Missing URL argument")
			cws.write(getCommandResponse(cmd, err))
			return
		}
		_, err := cws.player.InsertSongs(cmd.Arguments[0], 0)
		cws.write(getCommandResponse(cmd, err))
	case "play":
		_, err := cws.player.Play()
		cws.write(getCommandResponse(cmd, err))
	case "pause":
		err := cws.player.Pause()
		cws.write(getCommandResponse(cmd, err))
	case "status":
		song, remaining := cws.player.GetCurrentSong()
		resp := getCommandResponse(cmd, nil)
		resp.Status = &Status{
			Status:  cws.player.GetStatus(),
			Current: getAPISong(song, remaining),
			List:    getAPISongs(cws.player.GetQueuedSongs()),
		}
		cws.write(resp)
	case "next":
		_, err := cws.player.Next()
		cws.write(getCommandResponse(cmd, err))
	case "stop":
		err := cws.player.Stop()
		cws.write(getCommandResponse(cmd, err))
	case "empty-list":
		cws.player.EmptyQueue()
		cws.write(getCommandResponse(cmd, nil))
	case "shuffle-list":
		cws.player.ShuffleQueue()
		cws.write(getCommandResponse(cmd, nil))
	}
}

func (cws *ControlWebsocket) closeConnection() {
	// Use the write lock to ensure this function is _really_ called once.
	cws.writeLock.Lock()
	defer cws.writeLock.Unlock()

	if cws.hasClosed {
		return
	}
	cws.hasClosed = true

	// Close websocket
	cws.ws.Close()

	// Remove our event capturer
	cws.player.RemoveCapturer(cws.capturer)
}

func (cws *ControlWebsocket) write(data interface{}) {
	// Applications are responsible for ensuring that no more than one goroutine calls the write methods
	// (From the docs)
	cws.writeLock.Lock()
	cws.ws.SetWriteDeadline(time.Now().Add(writeWait))
	cws.ws.WriteJSON(data)
	cws.writeLock.Unlock()
}
<|endoftext|>


<commit_before>package vision

import (
	"image"
	"sync"
)

type ShadowCastMap interface {
	SetVisible(p image.Point)
	IsTransparent(p image.Point) bool
}

func ShadowCast(m ShadowCastMap, r Radius, source image.Point) {
	vt := visionTransformer{source: source}
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose())
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invy))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invy))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invy, invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invy, invx))
}

func ShadowCastPar(m ShadowCastMap, r Radius, source image.Point) {
	vt := visionTransformer{source: source}
	wg := &sync.WaitGroup{}
	wg.Add(4)
	go shadowCastPar(wg, m, r, vt.compose())
	go shadowCastPar(wg, m, r, vt.compose(invx))
	go shadowCastPar(wg, m, r, vt.compose(invy))
	go shadowCastPar(wg, m, r, vt.compose(invy, invx))
	wg.Wait()
	wg.Add(4)
	go shadowCastPar(wg, m, r, vt.compose(swap))
	go shadowCastPar(wg, m, r, vt.compose(swap, invx))
	go shadowCastPar(wg, m, r, vt.compose(swap, invy))
	go shadowCastPar(wg, m, r, vt.compose(swap, invy, invx))
	wg.Wait()
}

func shadowCastPar(wg *sync.WaitGroup, m ShadowCastMap, r Radius, trans visionTransform) {
	defer wg.Done()
	shadowCastOctant(1, 1.0, 0.0, m, r, trans)
}

func shadowCastOctant(col int, startSlope, endSlope float64, m ShadowCastMap, r Radius, trans visionTransform) {
	wall := false
	for x := col; startSlope > endSlope && !wall && r.In(x, 0); x++ {
		approxStart := int(startSlope*float64(x)) + 1
		for y := approxStart; y >= 0; y-- {
			if !r.In(x, y) {
				continue
			}
			hiSlope := (float64(y) - 0.5) / (float64(x) - 0.5)
			if hiSlope > startSlope {
				continue
			}
			loSlope := (float64(y) + 0.5) / (float64(x) - 0.5)
			if loSlope < endSlope {
				break
			}
			pos := trans(image.Point{X: x, Y: y})
			m.SetVisible(pos)
			if !m.IsTransparent(pos) {
				if !wall {
					wall = true
					shadowCastOctant(x+1, startSlope, loSlope, m, r, trans)
				}
			} else {
				if wall {
					wall = false
					startSlope = (float64(y) + 0.5) / (float64(x) + 0.5)
				}
			}
		}
	}
}
<commit_msg>Par fov is slow<commit_after>package vision

import "image"

type ShadowCastMap interface {
	SetVisible(p image.Point)
	IsTransparent(p image.Point) bool
}

func ShadowCast(m ShadowCastMap, r Radius, source image.Point) {
	vt := visionTransformer{source: source}
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose())
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invy))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invy))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(invy, invx))
	shadowCastOctant(1, 1.0, 0.0, m, r, vt.compose(swap, invy, invx))
}

func shadowCastOctant(col int, startSlope, endSlope float64, m ShadowCastMap, r Radius, trans visionTransform) {
	wall := false
	for x := col; startSlope > endSlope && !wall && r.In(x, 0); x++ {
		approxStart := int(startSlope*float64(x)) + 1
		for y := approxStart; y >= 0; y-- {
			if !r.In(x, y) {
				continue
			}
			hiSlope := (float64(y) - 0.5) / (float64(x) - 0.5)
			if hiSlope > startSlope {
				continue
			}
			loSlope := (float64(y) + 0.5) / (float64(x) - 0.5)
			if loSlope < endSlope {
				break
			}
			pos := trans(image.Point{X: x, Y: y})
			m.SetVisible(pos)
			if !m.IsTransparent(pos) {
				if !wall {
					wall = true
					shadowCastOctant(x+1, startSlope, loSlope, m, r, trans)
				}
			} else {
				if wall {
					wall = false
					startSlope = (float64(y) + 0.5) / (float64(x) + 0.5)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// 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 kubernetes

import (
	"encoding/json"
	"fmt"
	"github.com/romana/core/common"
	"github.com/romana/core/tenant"
	"log"
	"net/http"
)

const (
	selector = "podSelector"
)

// Done is an alias for empty struct, used to make broadcast channels
// for terminating goroutines.
type Done struct{}

/*
{"type":"ADDED","object":{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"d10db271-dc03-11e5-9c86-0213e1312dc5","resourceVersion":"6","creationTimestamp":"2016-02-25T21:07:45Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}}
*/

// Event is a representation of a structure that we receive from kubernetes API.
type Event struct {
	Type   string     `json:"Type"`
	Object KubeObject `json:"object"`
}

const (
	KubeEventAdded         = "ADDED"
	KubeEventDeleted       = "DELETED"
	KubeEventModified      = "MODIFIED"
	InternalEventDeleteAll = "_DELETE_ALL"
)

// KubeObject is a representation of object in kubernetes.
type KubeObject struct {
	Kind       string            `json:"kind"`
	Spec       Spec              `json:"spec"`
	ApiVersion string            `json:"apiVersion"`
	Metadata   Metadata          `json:"metadata"`
	Status     map[string]string `json:"status,omitempty"`
}

// makeId makes id to identify kube object.
func (o KubeObject) makeId() string {
	id := o.Metadata.Name + "/" + o.Metadata.Namespace
	return id
}

type PodSelector map[string]string

type FromEntry struct {
	Pods PodSelector `json:"pods"`
}

type AllowIncoming struct {
	From    []FromEntry `json:"from"`
	ToPorts []ToPort    `json:"toPorts"`
}

type ToPort struct {
	Port     uint   `json:"port"`
	Protocol string `json:"protocol"`
}

// TODO need to find a way to use different specs for different resources.
type Spec struct {
	AllowIncoming AllowIncoming `json:"allowIncoming"`
	PodSelector   PodSelector   `json:"podSelector"`
}

// Metadata is a representation of metadata in kubernetes object
type Metadata struct {
	Name              string            `json:"name"`
	Namespace         string            `json:"namespace"`
	SelfLink          string            `json:"selfLink"`
	Uid               string            `json:"uid"`
	ResourceVersion   string            `json:"resourceVersion"`
	CreationTimestamp string            `json:"creationTimestamp"`
	Labels            map[string]string `json:"labels"`
	Annotations       map[string]string `json:"annotations,omitempty"`
}

// handle kubernetes events according to their type.
func (e Event) handle(l *kubeListener) {
	log.Printf("Processing %s request for %s", e.Type, e.Object.Metadata.Name)

	if e.Object.Kind == "NetworkPolicy" && e.Type != KubeEventModified {
		e.handleNetworkPolicyEvent(l)
	} else if e.Object.Kind == "Namespace" {
		e.handleNamespaceEvent(l)
	} else {
		log.Printf("Received unindentified request %s for %s", e.Type, e.Object.Metadata.Name)
	}
}

// handleNetworkPolicyEvent by creating or deleting romana policies.
func (e Event) handleNetworkPolicyEvent(l *kubeListener) {
	var action networkPolicyAction
	if e.Type == KubeEventAdded {
		action = networkPolicyActionAdd
	} else {
		action = networkPolicyActionDelete
	}
	policy, err := l.translateNetworkPolicy(&e.Object)
	if err == nil {
		j1, _ := json.Marshal(e)
		j2, _ := json.Marshal(policy)
		log.Printf("handleNetworkPolicyEvent(): translated\n\t%s\n\tto\n\t%s", j1, j2)
		l.applyNetworkPolicy(action, policy)
	} else {
		log.Println(err)
	}
}

// handleNamespaceEvent by creating or deleting romana tenants.
func (e Event) handleNamespaceEvent(l *kubeListener) {
	log.Printf("Processing namespace event == %v and phase %v", e.Type, e.Object.Status)

	if e.Type == KubeEventAdded {
		tenantReq := tenant.Tenant{Name: e.Object.Metadata.Name, ExternalID: e.Object.Metadata.Name}
		tenantResp := tenant.Tenant{}
		log.Printf("processor: Posting to /tenants: %#v", tenantReq)
		tenantUrl, err := l.restClient.GetServiceUrl("tenant")
		if err != nil {
			log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
		} else {
			err := l.restClient.Post(fmt.Sprintf("%s/tenants", tenantUrl), tenantReq, &tenantResp)
			if err != nil {
				log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
			} else {
				log.Printf("Added tenant: %#v", tenantResp)
			}
		}
	} else {
		// TODO finish once UUID is merged
		// tenantReq := tenant.Tenant{Name: e.Object.Metadata.Name}
		// tenantResp := tenant.Tenant{}
		// err = client.Delete("/tenants", tenantReq, &tenantResp)
		// if err != nil {
		// 	log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
		// } else {
		// 	log.Printf("Added tenant: %#v", tenantResp)
		// }
	}

	// Ignore repeated events during namespace termination
	if e.Object.Status["phase"] == "Terminating" {
		if e.Type != KubeEventModified {
			e.Object.handleAnnotations(l)
		}
	} else {
		e.Object.handleAnnotations(l)
	}

}

// handleAnnotations on a namespace by implementing extra features requested through the annotation
func (o KubeObject) handleAnnotations(l *kubeListener) {
	log.Printf("In handleAnnotations")

	if o.Kind != "Namespace" {
		log.Printf("Error handling annotations on a namespace - object is not a namespace %s \n", o.Kind)
		return
	}

	CreateDefaultPolicy(o, l)
}

func CreateDefaultPolicy(o KubeObject, l *kubeListener) {
	log.Printf("In CreateDefaultPolicy for %v\n", o)
	tenant, _, err := l.resolveTenantByName(o.Metadata.Name)
	if err != nil {
		log.Printf("In CreateDefaultPolicy :: Error :: failed to resolve tenant %s \n", err)
	}

	policyName := fmt.Sprintf("ns%d", tenant.Seq)

	romanaPolicy := &common.Policy{
		Direction: common.PolicyDirectionIngress,
		Name:      policyName,
		AppliedTo: []common.Endpoint{{TenantNetworkID: &tenant.Seq}},
		Peers:     []common.Endpoint{{Peer: "any"}},
		Rules:     []common.Rule{{Protocol: "any"}},
	}

	log.Printf("In CreateDefaultPolicy with policy %v\n", romanaPolicy)

	var desiredAction networkPolicyAction

	if isolation, ok := o.Metadata.Annotations["net.alpha.kubernetes.io/network-isolation"]; ok {
		log.Printf("Handling default policy on a namespace %s, isolation is now %s \n", o.Metadata.Name, isolation)
		switch isolation {
		case "on":
			desiredAction = networkPolicyActionAdd
		case "off":
			desiredAction = networkPolicyActionDelete
		default:
			log.Printf("In CreateDefaultPolicy :: Error :: unrecognised annotation on a namespace %s is %s (expected on|off) \n",
				o.Metadata.Name, isolation)
			return
		}

	} else {
		log.Printf("Handling default policy on a namespace, no annotation detected assuming non isolated namespace\n")
		desiredAction = networkPolicyActionAdd
	}

	if err2 := l.applyNetworkPolicy(desiredAction, *romanaPolicy); err2 != nil {
		log.Printf("In CreateDefaultPolicy :: Error :: failed to apply %v to the policy %s \n", desiredAction, err)
	}
}

// watchEvents maintains goroutine fired by NsWatch, restarts it in case HTTP GET times out.
func (l *kubeListener) watchEvents(done <-chan Done, url string, resp *http.Response, out chan Event) {
	log.Println("Received namespace related event from kubernetes", resp.Body)

	dec := json.NewDecoder(resp.Body)
	var e Event

	for {
		select {
		case <-done:
			return
		default:
			// Flush e to ensure nothing gets carried over
			e = Event{}

			// Attempting to read event from HTTP connection
			err := dec.Decode(&e)
			if err != nil {
				// If fail
				log.Printf("Failed to decode message from connection %s due to %s\n. Attempting to re-establish", url, err)
				// Then stop all goroutines
				out <- Event{Type: InternalEventDeleteAll}

				// And try to re-establish HTTP connection
				resp, err2 := http.Get(url)
				if err2 != nil {
					log.Printf("Failed establish connection %s due to %s\n.", url, err)
				} else if err2 == nil {
					dec = json.NewDecoder(resp.Body)
				}
			} else {
				// Else submit event
				out <- e
			}
		}

	}
}

// NsWatch is a generator that watches namespace related events in
// kubernetes API and publishes this events to a channel.
func (l *kubeListener) nsWatch(done <-chan Done, url string) (<-chan Event, error) {
	out := make(chan Event)

	resp, err := http.Get(url)
	if err != nil {
		return out, err
	}

	go l.watchEvents(done, url, resp, out)

	return out, nil
}

// Produce method listens for resource updates happening within given namespace
// and publishes these updates in a channel.
func (ns KubeObject) produce(out chan Event, done <-chan Done, kubeListener *kubeListener) error {
	url, err := common.CleanURL(fmt.Sprintf("%s/%s/%s%s", kubeListener.kubeURL, kubeListener.policyNotificationPathPrefix, ns.Metadata.Name, kubeListener.policyNotificationPathPostfix))
	if err != nil {
		return err
	}
	log.Printf("Launching producer to listen for policy notifications on namespace %s at URL %s ", ns.Metadata.Name, url)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	go kubeListener.watchEvents(done, url, resp, out)

	return nil
}
<commit_msg>Fix kubernetes default policies logic in kube listener<commit_after>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// 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 kubernetes

import (
	"encoding/json"
	"fmt"
	"github.com/romana/core/common"
	"github.com/romana/core/tenant"
	"log"
	"net/http"
)

const (
	selector = "podSelector"
)

// Done is an alias for empty struct, used to make broadcast channels
// for terminating goroutines.
type Done struct{}

/*
{"type":"ADDED","object":{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"d10db271-dc03-11e5-9c86-0213e1312dc5","resourceVersion":"6","creationTimestamp":"2016-02-25T21:07:45Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}}
*/

// Event is a representation of a structure that we receive from kubernetes API.
type Event struct {
	Type   string     `json:"Type"`
	Object KubeObject `json:"object"`
}

const (
	KubeEventAdded         = "ADDED"
	KubeEventDeleted       = "DELETED"
	KubeEventModified      = "MODIFIED"
	InternalEventDeleteAll = "_DELETE_ALL"
)

// KubeObject is a representation of object in kubernetes.
type KubeObject struct {
	Kind       string            `json:"kind"`
	Spec       Spec              `json:"spec"`
	ApiVersion string            `json:"apiVersion"`
	Metadata   Metadata          `json:"metadata"`
	Status     map[string]string `json:"status,omitempty"`
}

// makeId makes id to identify kube object.
func (o KubeObject) makeId() string {
	id := o.Metadata.Name + "/" + o.Metadata.Namespace
	return id
}

type PodSelector map[string]string

type FromEntry struct {
	Pods PodSelector `json:"pods"`
}

type AllowIncoming struct {
	From    []FromEntry `json:"from"`
	ToPorts []ToPort    `json:"toPorts"`
}

type ToPort struct {
	Port     uint   `json:"port"`
	Protocol string `json:"protocol"`
}

// TODO need to find a way to use different specs for different resources.
type Spec struct {
	AllowIncoming AllowIncoming `json:"allowIncoming"`
	PodSelector   PodSelector   `json:"podSelector"`
}

// Metadata is a representation of metadata in kubernetes object
type Metadata struct {
	Name              string            `json:"name"`
	Namespace         string            `json:"namespace"`
	SelfLink          string            `json:"selfLink"`
	Uid               string            `json:"uid"`
	ResourceVersion   string            `json:"resourceVersion"`
	CreationTimestamp string            `json:"creationTimestamp"`
	Labels            map[string]string `json:"labels"`
	Annotations       map[string]string `json:"annotations,omitempty"`
}

// handle kubernetes events according to their type.
func (e Event) handle(l *kubeListener) {
	log.Printf("Processing %s request for %s", e.Type, e.Object.Metadata.Name)

	if e.Object.Kind == "NetworkPolicy" && e.Type != KubeEventModified {
		e.handleNetworkPolicyEvent(l)
	} else if e.Object.Kind == "Namespace" {
		e.handleNamespaceEvent(l)
	} else {
		log.Printf("Received unindentified request %s for %s", e.Type, e.Object.Metadata.Name)
	}
}

// handleNetworkPolicyEvent by creating or deleting romana policies.
func (e Event) handleNetworkPolicyEvent(l *kubeListener) {
	var action networkPolicyAction
	if e.Type == KubeEventAdded {
		action = networkPolicyActionAdd
	} else {
		action = networkPolicyActionDelete
	}
	policy, err := l.translateNetworkPolicy(&e.Object)
	if err == nil {
		j1, _ := json.Marshal(e)
		j2, _ := json.Marshal(policy)
		log.Printf("handleNetworkPolicyEvent(): translated\n\t%s\n\tto\n\t%s", j1, j2)
		l.applyNetworkPolicy(action, policy)
	} else {
		log.Println(err)
	}
}

// handleNamespaceEvent by creating or deleting romana tenants.
func (e Event) handleNamespaceEvent(l *kubeListener) {
	log.Printf("Processing namespace event == %v and phase %v", e.Type, e.Object.Status)

	if e.Type == KubeEventAdded {
		tenantReq := tenant.Tenant{Name: e.Object.Metadata.Name, ExternalID: e.Object.Metadata.Name}
		tenantResp := tenant.Tenant{}
		log.Printf("processor: Posting to /tenants: %#v", tenantReq)
		tenantUrl, err := l.restClient.GetServiceUrl("tenant")
		if err != nil {
			log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
		} else {
			err := l.restClient.Post(fmt.Sprintf("%s/tenants", tenantUrl), tenantReq, &tenantResp)
			if err != nil {
				log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
			} else {
				log.Printf("Added tenant: %#v", tenantResp)
			}
		}
	} else {
		// TODO finish once UUID is merged
		// tenantReq := tenant.Tenant{Name: e.Object.Metadata.Name}
		// tenantResp := tenant.Tenant{}
		// err = client.Delete("/tenants", tenantReq, &tenantResp)
		// if err != nil {
		// 	log.Printf("Error adding tenant %s: %#v", tenantReq.Name, err)
		// } else {
		// 	log.Printf("Added tenant: %#v", tenantResp)
		// }
	}

	// Ignore repeated events during namespace termination
	if e.Object.Status["phase"] == "Terminating" {
		if e.Type != KubeEventModified {
			e.Object.handleAnnotations(l)
		}
	} else {
		e.Object.handleAnnotations(l)
	}

}

// handleAnnotations on a namespace by implementing extra features requested through the annotation
func (o KubeObject) handleAnnotations(l *kubeListener) {
	log.Printf("In handleAnnotations")

	if o.Kind != "Namespace" {
		log.Printf("Error handling annotations on a namespace - object is not a namespace %s \n", o.Kind)
		return
	}

	CreateDefaultPolicy(o, l)
}

func CreateDefaultPolicy(o KubeObject, l *kubeListener) {
	log.Printf("In CreateDefaultPolicy for %v\n", o)
	tenant, _, err := l.resolveTenantByName(o.Metadata.Name)
	if err != nil {
		log.Printf("In CreateDefaultPolicy :: Error :: failed to resolve tenant %s \n", err)
	}

	policyName := fmt.Sprintf("ns%d", tenant.Seq)

	romanaPolicy := &common.Policy{
		Direction: common.PolicyDirectionIngress,
		Name:      policyName,
		AppliedTo: []common.Endpoint{{TenantNetworkID: &tenant.Seq}},
		Peers:     []common.Endpoint{{Peer: "any"}},
		Rules:     []common.Rule{{Protocol: "any"}},
	}

	log.Printf("In CreateDefaultPolicy with policy %v\n", romanaPolicy)

	var desiredAction networkPolicyAction

	if isolation, ok := o.Metadata.Annotations["net.alpha.kubernetes.io/network-isolation"]; ok {
		log.Printf("Handling default policy on a namespace %s, isolation is now %s \n", o.Metadata.Name, isolation)
		switch isolation {
		case "on":
			desiredAction = networkPolicyActionDelete
		case "off":
			desiredAction = networkPolicyActionAdd
		default:
			log.Printf("In CreateDefaultPolicy :: Error :: unrecognised annotation on a namespace %s is %s (expected on|off) \n",
				o.Metadata.Name, isolation)
			return
		}

	} else {
		log.Printf("Handling default policy on a namespace, no annotation detected assuming non isolated namespace\n")
		desiredAction = networkPolicyActionAdd
	}

	if err2 := l.applyNetworkPolicy(desiredAction, *romanaPolicy); err2 != nil {
		log.Printf("In CreateDefaultPolicy :: Error :: failed to apply %v to the policy %s \n", desiredAction, err)
	}
}

// watchEvents maintains goroutine fired by NsWatch, restarts it in case HTTP GET times out.
func (l *kubeListener) watchEvents(done <-chan Done, url string, resp *http.Response, out chan Event) {
	log.Println("Received namespace related event from kubernetes", resp.Body)

	dec := json.NewDecoder(resp.Body)
	var e Event

	for {
		select {
		case <-done:
			return
		default:
			// Flush e to ensure nothing gets carried over
			e = Event{}

			// Attempting to read event from HTTP connection
			err := dec.Decode(&e)
			if err != nil {
				// If fail
				log.Printf("Failed to decode message from connection %s due to %s\n. Attempting to re-establish", url, err)
				// Then stop all goroutines
				out <- Event{Type: InternalEventDeleteAll}

				// And try to re-establish HTTP connection
				resp, err2 := http.Get(url)
				if err2 != nil {
					log.Printf("Failed establish connection %s due to %s\n.", url, err)
				} else if err2 == nil {
					dec = json.NewDecoder(resp.Body)
				}
			} else {
				// Else submit event
				out <- e
			}
		}

	}
}

// NsWatch is a generator that watches namespace related events in
// kubernetes API and publishes this events to a channel.
func (l *kubeListener) nsWatch(done <-chan Done, url string) (<-chan Event, error) {
	out := make(chan Event)

	resp, err := http.Get(url)
	if err != nil {
		return out, err
	}

	go l.watchEvents(done, url, resp, out)

	return out, nil
}

// Produce method listens for resource updates happening within given namespace
// and publishes these updates in a channel.
func (ns KubeObject) produce(out chan Event, done <-chan Done, kubeListener *kubeListener) error {
	url, err := common.CleanURL(fmt.Sprintf("%s/%s/%s%s", kubeListener.kubeURL, kubeListener.policyNotificationPathPrefix, ns.Metadata.Name, kubeListener.policyNotificationPathPostfix))
	if err != nil {
		return err
	}
	log.Printf("Launching producer to listen for policy notifications on namespace %s at URL %s ", ns.Metadata.Name, url)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	go kubeListener.watchEvents(done, url, resp, out)

	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"fmt"
	"github.com/ixre/gof"
	"github.com/ixre/gof/api"
	"github.com/ixre/gof/storage"
	"github.com/ixre/gof/util"
	"go2o/core/domain/interface/registry"
	"go2o/core/infrastructure/domain"
	"go2o/core/service/auto_gen/rpc/member_service"
	"go2o/core/service/thrift"
	"log"
	"strconv"
	"strings"
	"time"
)

var _ api.Handler = new(RegisterApi)

// 注册接口API
type RegisterApi struct {
	utils
	st storage.Interface
}

func NewRegisterApi() api.Handler {
	st := gof.CurrentApp.Storage()
	return &RegisterApi{
		st: st,
	}
}

func (m RegisterApi) Process(fn string, ctx api.Context) *api.Response {
	return api.HandleMultiFunc(fn, ctx, map[string]api.HandlerFunc{
		"get_token": m.getToken,
		"send_code": m.sendRegisterCode,
		"submit":    m.submit,
	})
}

/**
 * @api {post} /register/submit 用户注册
 * @apiName submit
 * @apiGroup register
 * @apiParam {String} user 用户名
 * @apiParam {String} pwd 密码
 * @apiParam {String} phone 手机号
 * @apiParam {String} token 注册令牌
 * @apiParam {String} check_code 验证码, 如果手机注册时,需要填写
 * @apiParam {String} reg_from 注册来源
 * @apiParam {String} invite_code 邀请码
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) submit(ctx api.Context) interface{} {
	user := strings.TrimSpace(ctx.Form().GetString("user"))
	pwd := strings.TrimSpace(ctx.Form().GetString("pwd"))
	phone := strings.TrimSpace(ctx.Form().GetString("phone"))
	regFrom := strings.TrimSpace(ctx.Form().GetString("reg_from"))       // 注册来源
	checkCode := strings.TrimSpace(ctx.Form().GetString("check_code"))   // 验证码
	inviteCode := strings.TrimSpace(ctx.Form().GetString("invite_code")) // 邀请码
	regIp := strings.TrimSpace(ctx.Form().GetString("$user_addr"))       // IP地址
	token := strings.TrimSpace(ctx.Form().GetString("token"))
	if len(token) == 0 || !m.checkRegToken(token) {
		return api.ResponseWithCode(6, "非法注册请求")
	}
	if b := m.compareCheckCode(token, phone, checkCode); !b {
		return api.ResponseWithCode(7, "注册校验码不正确")
	}
	trans, cli, err := thrift.MemberServeClient()
	if err == nil {
		defer trans.Close()
		mp := map[string]string{
			"reg_ip":      regIp,
			"reg_from":    regFrom,
			"invite_code": inviteCode,
		}
		r, _ := cli.RegisterMemberV2(thrift.Context, user, pwd, 0, "", phone, "", "", mp)
		if r.ErrCode == 0 {
			//todo: 未生效
			m.signCheckTokenExpires(token)
		}
		return r
	}
	return m.SResult(err)
}

/**
 * @api {post} /register/get_token 获取注册Token
 * @apiName get_token
 * @apiGroup register
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) getToken(ctx api.Context) interface{} {
	rd := util.RandString(10)
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", rd)
	m.st.SetExpire(key, 0, 600)
	return rd
}

// 获取验证码的间隔时间
func (m RegisterApi) getDurationSecond() int64 {
	trans, cli, err := thrift.RegistryServeClient()
	if err == nil {
		val, _ := cli.GetRegistry(thrift.Context, registry.SmsSendDuration)
		trans.Close()
		i, err := strconv.Atoi(val)
		if err != nil {
			log.Println("[ Go2o][ Registry]: parse value error:", err.Error())
		}
		return int64(i)
	}
	return 120
}

// 检查短信验证码是否频繁发送
func (m RegisterApi) checkCodeDuration(token, phone string) error {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	nowUnix := time.Now().Unix()
	unix, err := m.st.GetInt64(key)

	log.Println("---", nowUnix, unix, key)

	if err == nil {
		if nowUnix-unix < m.getDurationSecond() {
			return errors.New("请勿在短时间内获取短信验证码!")
		}
	}
	return nil
}

// 标记验证码发送时间
func (m RegisterApi) signCheckCodeSendOk(token string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	unix := time.Now().Unix()
	log.Println("----save code:", unix)
	m.st.SetExpire(key, unix, 600)
}

// 验证注册令牌是否正确
func (m RegisterApi) checkRegToken(token string) bool {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	return m.st.Exists(key)
}

// 将注册令牌标记为过期
func (m RegisterApi) signCheckTokenExpires(token string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	m.st.Del(key)
}

// 存储校验数据
func (m RegisterApi) saveCheckCodeData(token string, phone string, code string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_code", token)
	key1 := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_phone", token)
	m.st.SetExpire(key, code, 600)
	m.st.SetExpire(key1, phone, 600)
}

// 获取校验结果
func (m RegisterApi) compareCheckCode(token, phone string, code string) bool {
	if len(phone) > 0 {
		key := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_code", token)
		key1 := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_phone", token)
		ckCode, _ := m.st.GetString(key)
		ckPhone, _ := m.st.GetString(key1)
		if ckPhone == "" || ckPhone != phone {
			return false
		}
		if ckCode == "" || ckCode != code {
			return false
		}
	}
	return true
}

/**
 * @api {post} /register/send_code 发送注册验证码
 * @apiName send_code
 * @apiGroup register
 * @apiParam {String} phone 手机号码
 * @apiParam {String} token 注册令牌
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) sendRegisterCode(ctx api.Context) interface{} {
	trans, cli, _ := thrift.RegistryServeClient()
	keys := []string{
		registry.MemberRegisterMustBindPhone,
		registry.SmsRegisterTemplateId,
		registry.EnableDebugMode,
	}
	mp, _ := cli.GetRegistries(thrift.Context, keys)
	trans.Close()
	allowPhoneAsUser := mp[keys[0]]
	debugMode := mp[keys[2]] == "true"
	if allowPhoneAsUser != "true" {
		return api.ResponseWithCode(2, "不允许使用手机号注册")
	}
	phone := strings.TrimSpace(ctx.Form().GetString("phone"))
	token := strings.TrimSpace(ctx.Form().GetString("token"))
	if len(token) == 0 {
		return api.ResponseWithCode(6, "非法注册请求")
	}
	err := m.checkCodeDuration(token, phone)
	if err == nil {
		// 检查手机号码是否被其他人使用
		trans, cli, _ := thrift.MemberServeClient()
		memberId, _ := cli.SwapMemberId(thrift.Context, member_service.ECredentials_Phone, phone)
		trans.Close()
		if memberId <= 0 {
			code := domain.NewCheckCode()
			m.saveCheckCodeData(token, phone, code)
			expiresMinutes := 10
			// 创建参数
			data := map[string]string{
				"code":       code,
				"operation":  "注册会员",
				"minutes":    strconv.Itoa(expiresMinutes),
				"templateId": mp[keys[1]],
			}
			// 构造并发送短信
			trans, cli, _ := thrift.MessageServeClient()
			defer trans.Close()
			n, _ := cli.GetNotifyItem(thrift.Context, "验证手机")
			// 测试环境不发送短信
			if debugMode {
				return api.ResponseWithCode(3, "【测试】短信验证码为:"+code)
			}
			// 发送短信
			r, _ := cli.SendPhoneMessage(thrift.Context, phone, n.Content, data)
			if r.ErrCode == 0 {
				m.signCheckCodeSendOk(code) // 标记为已发送
			} else {
				log.Println("[ Go2o][ Sms]: 验证码发送失败:", r.ErrMsg)
				return api.ResponseWithCode(3, "验证码发送失败")
			}
		} else {
			return api.ResponseWithCode(1, "手机号码已注册")
		}
	}
	return api.NewResponse(map[string]string{})
}
<commit_msg>register_api.go<commit_after>package api

import (
	"errors"
	"fmt"
	"github.com/ixre/gof"
	"github.com/ixre/gof/api"
	"github.com/ixre/gof/storage"
	"github.com/ixre/gof/util"
	"go2o/core/domain/interface/registry"
	"go2o/core/infrastructure/domain"
	"go2o/core/service/auto_gen/rpc/member_service"
	"go2o/core/service/thrift"
	"log"
	"strconv"
	"strings"
	"time"
)

var _ api.Handler = new(RegisterApi)

// 注册接口API
type RegisterApi struct {
	utils
	st storage.Interface
}

func NewRegisterApi() api.Handler {
	st := gof.CurrentApp.Storage()
	return &RegisterApi{
		st: st,
	}
}

func (m RegisterApi) Process(fn string, ctx api.Context) *api.Response {
	return api.HandleMultiFunc(fn, ctx, map[string]api.HandlerFunc{
		"get_token": m.getToken,
		"send_code": m.sendRegisterCode,
		"submit":    m.submit,
	})
}

/**
 * @api {post} /register/submit 用户注册
 * @apiName submit
 * @apiGroup register
 * @apiParam {String} user 用户名
 * @apiParam {String} pwd 密码
 * @apiParam {String} phone 手机号
 * @apiParam {String} token 注册令牌
 * @apiParam {String} check_code 验证码, 如果手机注册时,需要填写
 * @apiParam {String} reg_from 注册来源
 * @apiParam {String} invite_code 邀请码
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) submit(ctx api.Context) interface{} {
	user := strings.TrimSpace(ctx.Form().GetString("user"))
	pwd := strings.TrimSpace(ctx.Form().GetString("pwd"))
	phone := strings.TrimSpace(ctx.Form().GetString("phone"))
	regFrom := strings.TrimSpace(ctx.Form().GetString("reg_from"))       // 注册来源
	checkCode := strings.TrimSpace(ctx.Form().GetString("check_code"))   // 验证码
	inviteCode := strings.TrimSpace(ctx.Form().GetString("invite_code")) // 邀请码
	regIp := strings.TrimSpace(ctx.Form().GetString("$user_addr"))       // IP地址
	token := strings.TrimSpace(ctx.Form().GetString("token"))
	if len(token) == 0 || !m.checkRegToken(token) {
		return api.ResponseWithCode(6, "非法注册请求")
	}
	if b := m.compareCheckCode(token, phone, checkCode); !b {
		return api.ResponseWithCode(7, "注册校验码不正确")
	}
	trans, cli, err := thrift.MemberServeClient()
	if err == nil {
		defer trans.Close()
		mp := map[string]string{
			"reg_ip":      regIp,
			"reg_from":    regFrom,
			"invite_code": inviteCode,
		}
		r, _ := cli.RegisterMemberV2(thrift.Context, user, pwd, 0, "", phone, "", "", mp)
		if r.ErrCode == 0 {
			//todo: 未生效
			m.signCheckTokenExpires(token)
		}
		log.Println("----",fmt.Sprintf("%#v",r))
		return r
	}
	return m.SResult(err)
}

/**
 * @api {post} /register/get_token 获取注册Token
 * @apiName get_token
 * @apiGroup register
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) getToken(ctx api.Context) interface{} {
	rd := util.RandString(10)
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", rd)
	m.st.SetExpire(key, 0, 600)
	return rd
}

// 获取验证码的间隔时间
func (m RegisterApi) getDurationSecond() int64 {
	trans, cli, err := thrift.RegistryServeClient()
	if err == nil {
		val, _ := cli.GetRegistry(thrift.Context, registry.SmsSendDuration)
		trans.Close()
		i, err := strconv.Atoi(val)
		if err != nil {
			log.Println("[ Go2o][ Registry]: parse value error:", err.Error())
		}
		return int64(i)
	}
	return 120
}

// 检查短信验证码是否频繁发送
func (m RegisterApi) checkCodeDuration(token, phone string) error {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	nowUnix := time.Now().Unix()
	unix, err := m.st.GetInt64(key)

	log.Println("---", nowUnix, unix, key)

	if err == nil {
		if nowUnix-unix < m.getDurationSecond() {
			return errors.New("请勿在短时间内获取短信验证码!")
		}
	}
	return nil
}

// 标记验证码发送时间
func (m RegisterApi) signCheckCodeSendOk(token string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	unix := time.Now().Unix()
	log.Println("----save code:", unix)
	m.st.SetExpire(key, unix, 600)
}

// 验证注册令牌是否正确
func (m RegisterApi) checkRegToken(token string) bool {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	return m.st.Exists(key)
}

// 将注册令牌标记为过期
func (m RegisterApi) signCheckTokenExpires(token string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:last-time", token)
	m.st.Del(key)
}

// 存储校验数据
func (m RegisterApi) saveCheckCodeData(token string, phone string, code string) {
	key := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_code", token)
	key1 := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_phone", token)
	m.st.SetExpire(key, code, 600)
	m.st.SetExpire(key1, phone, 600)
}

// 获取校验结果
func (m RegisterApi) compareCheckCode(token, phone string, code string) bool {
	if len(phone) > 0 {
		key := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_code", token)
		key1 := fmt.Sprintf("sys:go2o:reg:token:%s:reg_check_phone", token)
		ckCode, _ := m.st.GetString(key)
		ckPhone, _ := m.st.GetString(key1)
		if ckPhone == "" || ckPhone != phone {
			return false
		}
		if ckCode == "" || ckCode != code {
			return false
		}
	}
	return true
}

/**
 * @api {post} /register/send_code 发送注册验证码
 * @apiName send_code
 * @apiGroup register
 * @apiParam {String} phone 手机号码
 * @apiParam {String} token 注册令牌
 * @apiSuccessExample Success-Response
 * {}
 * @apiSuccessExample Error-Response
 * {"code":1,"message":"api not defined"}
 */
func (m RegisterApi) sendRegisterCode(ctx api.Context) interface{} {
	trans, cli, _ := thrift.RegistryServeClient()
	keys := []string{
		registry.MemberRegisterMustBindPhone,
		registry.SmsRegisterTemplateId,
		registry.EnableDebugMode,
	}
	mp, _ := cli.GetRegistries(thrift.Context, keys)
	trans.Close()
	allowPhoneAsUser := mp[keys[0]]
	debugMode := mp[keys[2]] == "true"
	if allowPhoneAsUser != "true" {
		return api.ResponseWithCode(2, "不允许使用手机号注册")
	}
	phone := strings.TrimSpace(ctx.Form().GetString("phone"))
	token := strings.TrimSpace(ctx.Form().GetString("token"))
	if len(token) == 0 {
		return api.ResponseWithCode(6, "非法注册请求")
	}
	err := m.checkCodeDuration(token, phone)
	if err == nil {
		// 检查手机号码是否被其他人使用
		trans, cli, _ := thrift.MemberServeClient()
		memberId, _ := cli.SwapMemberId(thrift.Context, member_service.ECredentials_Phone, phone)
		trans.Close()
		if memberId <= 0 {
			code := domain.NewCheckCode()
			m.saveCheckCodeData(token, phone, code)
			expiresMinutes := 10
			// 创建参数
			data := map[string]string{
				"code":       code,
				"operation":  "注册会员",
				"minutes":    strconv.Itoa(expiresMinutes),
				"templateId": mp[keys[1]],
			}
			// 构造并发送短信
			trans, cli, _ := thrift.MessageServeClient()
			defer trans.Close()
			n, _ := cli.GetNotifyItem(thrift.Context, "验证手机")
			// 测试环境不发送短信
			if debugMode {
				return api.ResponseWithCode(3, "【测试】短信验证码为:"+code)
			}
			// 发送短信
			r, _ := cli.SendPhoneMessage(thrift.Context, phone, n.Content, data)
			if r.ErrCode == 0 {
				m.signCheckCodeSendOk(code) // 标记为已发送
			} else {
				log.Println("[ Go2o][ Sms]: 验证码发送失败:", r.ErrMsg)
				return api.ResponseWithCode(3, "验证码发送失败")
			}
		} else {
			return api.ResponseWithCode(1, "手机号码已注册")
		}
	}
	return api.NewResponse(map[string]string{})
}
<|endoftext|>


<commit_before>package jira

import (
	"github.com/coryb/oreo"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("jira")

const VERSION = "1.0.7"

type Jira struct {
	Endpoint string     `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
	UA       HttpClient `json:"-" yaml:"-"`
}

func NewJira(endpoint string) *Jira {
	return &Jira{
		Endpoint: endpoint,
		UA:       oreo.New(),
	}
}
<commit_msg>version bump<commit_after>package jira

import (
	"github.com/coryb/oreo"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("jira")

const VERSION = "1.0.8"

type Jira struct {
	Endpoint string     `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
	UA       HttpClient `json:"-" yaml:"-"`
}

func NewJira(endpoint string) *Jira {
	return &Jira{
		Endpoint: endpoint,
		UA:       oreo.New(),
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/gin-gonic/gin"
	"github.com/qor/i18n/inline_edit"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/config"
	"github.com/qor/qor-example/config/admin"
	"github.com/qor/qor-example/config/auth"
	"github.com/qor/qor-example/config/i18n"
	"github.com/qor/qor-example/db"
	"github.com/qor/seo"
	"github.com/qor/widget"
	"gopkg.in/authboss.v0"
	"html/template"
)

func CurrentUser(ctx *gin.Context) *models.User {
	userInter, err := auth.Auth.CurrentUser(ctx.Writer, ctx.Request)
	if userInter != nil && err == nil {
		return userInter.(*models.User)
	}
	return nil
}

func I18nFuncMap(ctx *gin.Context) template.FuncMap {
	return inline_edit.FuncMap(i18n.I18n, "en-US", CurrentUser(ctx) != nil)
}

func HomeIndex(ctx *gin.Context) {
	var products []models.Product
	db.DB.Limit(9).Preload("ColorVariations").Preload("ColorVariations.Images").Find(&products)
	seoObj := models.SEOSetting{}
	db.DB.First(&seoObj)

	widgetContext := widget.NewContext(map[string]interface{}{"Request": ctx.Request})

	config.View.Funcs(I18nFuncMap(ctx)).Execute(
		"home_index",
		gin.H{
			authboss.FlashSuccessKey: auth.Auth.FlashSuccess(ctx.Writer, ctx.Request),
			authboss.FlashErrorKey:   auth.Auth.FlashError(ctx.Writer, ctx.Request),
			"SeoTag":                 seoObj.HomePage.Render(seoObj, nil),
			"top_banner":             admin.Widgets.Render("Banner", "TopBanner", widgetContext, true),
			"feature_products":       admin.Widgets.Render("Products", "FeatureProducts", widgetContext, true),
			"Products":               products,
			"MicroSearch": seo.MicroSearch{
				URL:    "http://demo.getqor.com",
				Target: "http://demo.getqor.com/search?q={keyword}",
			}.Render(),
			"MicroContact": seo.MicroContact{
				URL:         "http://demo.getqor.com",
				Telephone:   "080-0012-3232",
				ContactType: "Customer Service",
			}.Render(),
			"CurrentUser": CurrentUser(ctx),
		},
		ctx.Request,
		ctx.Writer,
	)
}
<commit_msg>authboss: only login user could edit widget<commit_after>package controllers

import (
	"github.com/gin-gonic/gin"
	"github.com/qor/i18n/inline_edit"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/config"
	"github.com/qor/qor-example/config/admin"
	"github.com/qor/qor-example/config/auth"
	"github.com/qor/qor-example/config/i18n"
	"github.com/qor/qor-example/db"
	"github.com/qor/seo"
	"github.com/qor/widget"
	"gopkg.in/authboss.v0"
	"html/template"
)

func CurrentUser(ctx *gin.Context) *models.User {
	userInter, err := auth.Auth.CurrentUser(ctx.Writer, ctx.Request)
	if userInter != nil && err == nil {
		return userInter.(*models.User)
	}
	return nil
}

func I18nFuncMap(ctx *gin.Context) template.FuncMap {
	return inline_edit.FuncMap(i18n.I18n, "en-US", CurrentUser(ctx) != nil)
}

func HomeIndex(ctx *gin.Context) {
	var products []models.Product
	db.DB.Limit(9).Preload("ColorVariations").Preload("ColorVariations.Images").Find(&products)
	seoObj := models.SEOSetting{}
	db.DB.First(&seoObj)

	widgetContext := widget.NewContext(map[string]interface{}{"Request": ctx.Request})

	config.View.Funcs(I18nFuncMap(ctx)).Execute(
		"home_index",
		gin.H{
			authboss.FlashSuccessKey: auth.Auth.FlashSuccess(ctx.Writer, ctx.Request),
			authboss.FlashErrorKey:   auth.Auth.FlashError(ctx.Writer, ctx.Request),
			"SeoTag":                 seoObj.HomePage.Render(seoObj, nil),
			"top_banner":             admin.Widgets.Render("Banner", "TopBanner", widgetContext, CurrentUser(ctx) != nil),
			"feature_products":       admin.Widgets.Render("Products", "FeatureProducts", widgetContext, CurrentUser(ctx) != nil),
			"Products":               products,
			"MicroSearch": seo.MicroSearch{
				URL:    "http://demo.getqor.com",
				Target: "http://demo.getqor.com/search?q={keyword}",
			}.Render(),
			"MicroContact": seo.MicroContact{
				URL:         "http://demo.getqor.com",
				Telephone:   "080-0012-3232",
				ContactType: "Customer Service",
			}.Render(),
			"CurrentUser": CurrentUser(ctx),
		},
		ctx.Request,
		ctx.Writer,
	)
}
<|endoftext|>


<commit_before>package sdl

// #include <SDL2/SDL_events.h>
import "C"
import "unsafe"
import "reflect"
import "fmt"

const (
	FIRSTEVENT			= 0
	QUIT				= 0x100
	APP_TERMINATING			= 0x101
	APP_LOWMEMORY			= 0x102
	APP_WILLENTERBACKGROUND		= 0x103
	APP_DIDENTERBACKGROUND		= 0x104
	APP_WILLENTERFOREGROUND		= 0x105
	APP_DIDENTERFOREGROUND		= 0x106

	/* Window events */
	WINDOWEVENT			= 0x200
	SYSWMEVENT			= 0x201

	/* Keyboard events */
	KEYDOWN				= 0x300
	KEYUP				= 0x301
	TEXTEDITING			= 0x302
	TEXTINPUT			= 0x303

	/* Mouse events */
	MOUSEMOTION			= 0x400
	MOUSEBUTTONDOWN			= 0x401
	MOUSEBUTTONUP			= 0x402
	MOUSEWHEEL			= 0x403

	/* Joystick events */
	JOYAXISMOTION			= 0x600
	JOYBALLMOTION			= 0x601
	JOYHATMOTION			= 0x602
	JOYBUTTONDOWN			= 0x603
	JOYBUTTONUP			= 0x604
	JOYDEVICEADDED			= 0x605
	JOYDEVICEREMOVED		= 0x606

	/* Game controller events */
	CONTROLLERAXISMOTION		= 0x650
	CONTROLLERBUTTONDOWN		= 0x651
	CONTROLLERBUTTONUP		= 0x652
	CONTROLLERDEVICEADDED		= 0x653
	CONTROLLERDEVICEREMOVED		= 0x654
	CONTROLLERDEVICEREMAPPED	= 0x655

	/* Touch events */
	FINGERDOWN			= 0x700
	FINGERUP			= 0x701
	FINGERMOTION			= 0x702

	/* Gesture events */
	DOLLARGESTURE			= 0x800
	DOLLARRECORD			= 0x801
	MULTIGESTURE			= 0x802

	/* Clipboard events */
	CLIPBOARDUPDATE			= 0x900

	/* Drag and drop events */
	DROPFILE			= 0x1000

	USEREVENT			= 0x8000
	LASTEVENT			= 0xFFFF
)

const (
	ADDEVENT	= iota
	PEEKEVENT
	GETEVENT
)

const (
	QUERY		= -1
	IGNORE		= 0
	DISABLE		= 0
	ENABLE		= 1
)

type Event interface {}

type CEvent struct {
	Type uint32
	padding1 [52]byte
}

type Scancode uint32

type CommonEvent struct {
	Type uint32
	Timestamp uint32
}

type WindowEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Event uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Data1 int32
	Data2 int32
}

type KeyDownEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	State uint8
	Repeat uint8
	padding1 uint8
	padding2 uint8
	Keysym Keysym
}

type KeyUpEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	State uint8
	Repeat uint8
	padding1 uint8
	padding2 uint8
	Keysym Keysym
}

type TextEditingEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Text [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte;
	Start int32
	Length int32
}

type TextInputEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Text [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte;
}

type MouseMotionEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	State uint32
	X int32
	Y int32
	XRel int32
	YRel int32
}

type MouseButtonEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
	X int32
	Y int32
}

type MouseWheelEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	X int32
	Y int32
}

type JoyAxisEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Axis uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Value int16
	padding4 uint16
}

type JoyBallEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Ball uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	XRel int16
	YRel int16
}

type JoyHatEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Hat uint8
	Value uint8
	padding1 uint8
	padding2 uint8
}

type JoyButtonEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
}

type JoyDeviceEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
}

type ControllerAxisEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Axis uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Value int16
	padding4 uint16
}

type ControllerButtonEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
}

type ControllerDeviceEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
}

type TouchFingerEvent struct {
	Type uint32
	Timestamp uint32
	TouchID TouchID
	FingerID FingerID
	X float32
	Y float32
	DX float32
	DY float32
	Pressure float32
}

type MultiGestureEvent struct {
	Type uint32
	Timestamp uint32
	TouchId TouchID
	DTheta float32
	DDist float32
	X float32
	Y float32
	NumFingers uint16
	padding uint16
}

type DollarGestureEvent struct {
	Type uint32
	Timestamp uint32
	TouchID TouchID
	GestureID GestureID
	NumFingers uint32
	Error float32
	X float32
	Y float32
}

type DropEvent struct {
	Type uint32
	Timestamp uint32
	file unsafe.Pointer
}

type QuitEvent struct {
	Type uint32
	Timestamp uint32
}

type OSEvent struct {
	Type uint32
	Timestamp uint32
}

type ClipboardEvent struct {
	Type uint32
	Timestamp uint32
}

type UserEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Code int32
	Data1 unsafe.Pointer
	Data2 unsafe.Pointer
}

type SysWMEvent struct {
	Type uint32
	Timestamp uint32
	msg unsafe.Pointer
}

type EventFilter C.SDL_EventFilter

func PumpEvents() {
	C.SDL_PumpEvents()
}

func PeepEvents(events *Event, numevents int, action, minType, maxType uint32) int {
	_events := (*C.SDL_Event) (unsafe.Pointer(events))
	_numevents := (C.int) (numevents)
	_action := (C.SDL_eventaction) (action)
	_mintype := (C.Uint32) (minType)
	_maxtype := (C.Uint32) (maxType)
	return (int) (C.SDL_PeepEvents(_events, _numevents, _action, _mintype, _maxtype))
}

func HasEvent(type_ uint32) bool {
	_type := (C.Uint32) (type_)
	return C.SDL_HasEvent(_type) != 0
}

func HasEvents(minType, maxType uint32) bool {
	_minType := (C.Uint32) (minType)
	_maxType := (C.Uint32) (maxType)
	return C.SDL_HasEvents(_minType, _maxType) != 0
}

func FlushEvent(type_ uint32) {
	_type := (C.Uint32) (type_)
	C.SDL_FlushEvent(_type)
}

func FlushEvents(minType, maxType uint32) {
	_minType := (C.Uint32) (minType)
	_maxType := (C.Uint32) (maxType)
	C.SDL_FlushEvents(_minType, _maxType)
}

func PollEvent() Event {
	var cevent C.SDL_Event
	ret := C.SDL_PollEvent(&cevent)
	if ret == 0 {
		return nil
	}
	return goEvent((*CEvent)(unsafe.Pointer(&cevent)))
}

func goEvent(cevent *CEvent) Event {
	switch cevent.Type {
	case WINDOWEVENT:
		return (*WindowEvent) (unsafe.Pointer(cevent))
	case SYSWMEVENT:
		return (*SysWMEvent) (unsafe.Pointer(cevent))
	case KEYDOWN:
		return (*KeyDownEvent) (unsafe.Pointer(cevent))
	case KEYUP:
		return (*KeyUpEvent) (unsafe.Pointer(cevent))
	case TEXTEDITING:
		return (*TextEditingEvent) (unsafe.Pointer(cevent))
	case TEXTINPUT:
		return (*TextInputEvent) (unsafe.Pointer(cevent))
	case MOUSEMOTION:
		return (*MouseMotionEvent) (unsafe.Pointer(cevent))
	case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
		return (*MouseButtonEvent) (unsafe.Pointer(cevent))
	case MOUSEWHEEL:
		return (*MouseWheelEvent) (unsafe.Pointer(cevent))
	case JOYAXISMOTION:
		return (*JoyAxisEvent) (unsafe.Pointer(cevent))
	case JOYBALLMOTION:
		return (*JoyBallEvent) (unsafe.Pointer(cevent))
	case JOYHATMOTION:
		return (*JoyHatEvent) (unsafe.Pointer(cevent))
	case JOYBUTTONDOWN, JOYBUTTONUP:
		return (*JoyButtonEvent) (unsafe.Pointer(cevent))
	case JOYDEVICEADDED, JOYDEVICEREMOVED:
		return (*JoyDeviceEvent) (unsafe.Pointer(cevent))
	case CONTROLLERAXISMOTION:
		return (*ControllerAxisEvent) (unsafe.Pointer(cevent))
	case CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP:
		return (*ControllerButtonEvent) (unsafe.Pointer(cevent))
	case CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED, CONTROLLERDEVICEREMAPPED:
		return (*ControllerDeviceEvent) (unsafe.Pointer(cevent))
	case FINGERDOWN, FINGERUP, FINGERMOTION:
		return (*TouchFingerEvent) (unsafe.Pointer(cevent))
	case DOLLARGESTURE, DOLLARRECORD:
		return (*DollarGestureEvent) (unsafe.Pointer(cevent))
	case MULTIGESTURE:
		return (*MultiGestureEvent) (unsafe.Pointer(cevent))
	case DROPFILE:
		return (*DropEvent) (unsafe.Pointer(cevent))
	case QUIT:
		return (*QuitEvent) (unsafe.Pointer(cevent))
	case USEREVENT:
		return (*UserEvent) (unsafe.Pointer(cevent))
	case CLIPBOARDUPDATE:
		return (*ClipboardEvent) (unsafe.Pointer(cevent))
	}

	panic(fmt.Errorf("Unknown event type: %v", cevent.Type))
}

func cEvent(event Event) *CEvent {
	evv := reflect.ValueOf(event)
	return (*CEvent) (unsafe.Pointer(evv.UnsafeAddr()))
}

func WaitEventTimeout(event *Event, timeout int) int {
	_event := (*C.SDL_Event) (unsafe.Pointer(event))
	_timeout := (C.int) (timeout)
	return (int) (C.SDL_WaitEventTimeout(_event, _timeout))
}

func WaitEvent(event *Event) int {
	var cevent CEvent
	ok := (int) (C.SDL_WaitEvent((*C.SDL_Event)(unsafe.Pointer(&cevent))))
	if ok == 0 {
		return ok
	}
	*event = goEvent(&cevent)
	return ok
}

func PushEvent(event *Event) int {
	_event := (*C.SDL_Event) (unsafe.Pointer(event))
	return (int) (C.SDL_PushEvent(_event))
}

/* TODO: implement SDL_EventFilter functions */

func EventState(type_ uint32, state int) uint8 {
	_type := (C.Uint32) (type_)
	_state := (C.int) (state)
	return (uint8) (C.SDL_EventState(_type, _state))
}

func GetEventState(type_ uint32) uint8 {
	_type := (C.Uint32) (type_)
	return (uint8) (C.SDL_EventState(_type, QUERY))
}

func RegisterEvents(numevents int) uint32 {
	_numevents := (C.int) (numevents)
	return (uint32) (C.SDL_RegisterEvents(_numevents))
}
<commit_msg>Test fixes on WaitEvent(), WaitEventTimeout(), PushEvent(), and PeepEvents<commit_after>package sdl

// #include <SDL2/SDL_events.h>
import "C"
import "unsafe"
import "reflect"
import "fmt"

const (
	FIRSTEVENT			= 0
	QUIT				= 0x100
	APP_TERMINATING			= 0x101
	APP_LOWMEMORY			= 0x102
	APP_WILLENTERBACKGROUND		= 0x103
	APP_DIDENTERBACKGROUND		= 0x104
	APP_WILLENTERFOREGROUND		= 0x105
	APP_DIDENTERFOREGROUND		= 0x106

	/* Window events */
	WINDOWEVENT			= 0x200
	SYSWMEVENT			= 0x201

	/* Keyboard events */
	KEYDOWN				= 0x300
	KEYUP				= 0x301
	TEXTEDITING			= 0x302
	TEXTINPUT			= 0x303

	/* Mouse events */
	MOUSEMOTION			= 0x400
	MOUSEBUTTONDOWN			= 0x401
	MOUSEBUTTONUP			= 0x402
	MOUSEWHEEL			= 0x403

	/* Joystick events */
	JOYAXISMOTION			= 0x600
	JOYBALLMOTION			= 0x601
	JOYHATMOTION			= 0x602
	JOYBUTTONDOWN			= 0x603
	JOYBUTTONUP			= 0x604
	JOYDEVICEADDED			= 0x605
	JOYDEVICEREMOVED		= 0x606

	/* Game controller events */
	CONTROLLERAXISMOTION		= 0x650
	CONTROLLERBUTTONDOWN		= 0x651
	CONTROLLERBUTTONUP		= 0x652
	CONTROLLERDEVICEADDED		= 0x653
	CONTROLLERDEVICEREMOVED		= 0x654
	CONTROLLERDEVICEREMAPPED	= 0x655

	/* Touch events */
	FINGERDOWN			= 0x700
	FINGERUP			= 0x701
	FINGERMOTION			= 0x702

	/* Gesture events */
	DOLLARGESTURE			= 0x800
	DOLLARRECORD			= 0x801
	MULTIGESTURE			= 0x802

	/* Clipboard events */
	CLIPBOARDUPDATE			= 0x900

	/* Drag and drop events */
	DROPFILE			= 0x1000

	USEREVENT			= 0x8000
	LASTEVENT			= 0xFFFF
)

const (
	ADDEVENT	= iota
	PEEKEVENT
	GETEVENT
)

const (
	QUERY		= -1
	IGNORE		= 0
	DISABLE		= 0
	ENABLE		= 1
)

type Event interface {}

type CEvent struct {
	Type uint32
	padding1 [52]byte
}

type Scancode uint32

type CommonEvent struct {
	Type uint32
	Timestamp uint32
}

type WindowEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Event uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Data1 int32
	Data2 int32
}

type KeyDownEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	State uint8
	Repeat uint8
	padding1 uint8
	padding2 uint8
	Keysym Keysym
}

type KeyUpEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	State uint8
	Repeat uint8
	padding1 uint8
	padding2 uint8
	Keysym Keysym
}

type TextEditingEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Text [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte;
	Start int32
	Length int32
}

type TextInputEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Text [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte;
}

type MouseMotionEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	State uint32
	X int32
	Y int32
	XRel int32
	YRel int32
}

type MouseButtonEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
	X int32
	Y int32
}

type MouseWheelEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Which uint32
	X int32
	Y int32
}

type JoyAxisEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Axis uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Value int16
	padding4 uint16
}

type JoyBallEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Ball uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	XRel int16
	YRel int16
}

type JoyHatEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Hat uint8
	Value uint8
	padding1 uint8
	padding2 uint8
}

type JoyButtonEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
}

type JoyDeviceEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
}

type ControllerAxisEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Axis uint8
	padding1 uint8
	padding2 uint8
	padding3 uint8
	Value int16
	padding4 uint16
}

type ControllerButtonEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
	Button uint8
	State uint8
	padding1 uint8
	padding2 uint8
}

type ControllerDeviceEvent struct {
	Type uint32
	Timestamp uint32
	Which JoystickID
}

type TouchFingerEvent struct {
	Type uint32
	Timestamp uint32
	TouchID TouchID
	FingerID FingerID
	X float32
	Y float32
	DX float32
	DY float32
	Pressure float32
}

type MultiGestureEvent struct {
	Type uint32
	Timestamp uint32
	TouchId TouchID
	DTheta float32
	DDist float32
	X float32
	Y float32
	NumFingers uint16
	padding uint16
}

type DollarGestureEvent struct {
	Type uint32
	Timestamp uint32
	TouchID TouchID
	GestureID GestureID
	NumFingers uint32
	Error float32
	X float32
	Y float32
}

type DropEvent struct {
	Type uint32
	Timestamp uint32
	file unsafe.Pointer
}

type QuitEvent struct {
	Type uint32
	Timestamp uint32
}

type OSEvent struct {
	Type uint32
	Timestamp uint32
}

type ClipboardEvent struct {
	Type uint32
	Timestamp uint32
}

type UserEvent struct {
	Type uint32
	Timestamp uint32
	WindowID uint32
	Code int32
	Data1 unsafe.Pointer
	Data2 unsafe.Pointer
}

type SysWMEvent struct {
	Type uint32
	Timestamp uint32
	msg unsafe.Pointer
}

type EventFilter C.SDL_EventFilter

func PumpEvents() {
	C.SDL_PumpEvents()
}

func PeepEvents(events []Event, numevents int, action, minType, maxType uint32) int {
	_events := (*C.SDL_Event) (unsafe.Pointer(cEvent(&events[0])))
	_numevents := (C.int) (numevents)
	_action := (C.SDL_eventaction) (action)
	_mintype := (C.Uint32) (minType)
	_maxtype := (C.Uint32) (maxType)
	return (int) (C.SDL_PeepEvents(_events, _numevents, _action, _mintype, _maxtype))
}

func HasEvent(type_ uint32) bool {
	_type := (C.Uint32) (type_)
	return C.SDL_HasEvent(_type) != 0
}

func HasEvents(minType, maxType uint32) bool {
	_minType := (C.Uint32) (minType)
	_maxType := (C.Uint32) (maxType)
	return C.SDL_HasEvents(_minType, _maxType) != 0
}

func FlushEvent(type_ uint32) {
	_type := (C.Uint32) (type_)
	C.SDL_FlushEvent(_type)
}

func FlushEvents(minType, maxType uint32) {
	_minType := (C.Uint32) (minType)
	_maxType := (C.Uint32) (maxType)
	C.SDL_FlushEvents(_minType, _maxType)
}

func PollEvent() Event {
	var cevent C.SDL_Event
	ret := C.SDL_PollEvent(&cevent)
	if ret == 0 {
		return nil
	}
	return goEvent((*CEvent)(unsafe.Pointer(&cevent)))
}

func goEvent(cevent *CEvent) Event {
	switch cevent.Type {
	case WINDOWEVENT:
		return (*WindowEvent) (unsafe.Pointer(cevent))
	case SYSWMEVENT:
		return (*SysWMEvent) (unsafe.Pointer(cevent))
	case KEYDOWN:
		return (*KeyDownEvent) (unsafe.Pointer(cevent))
	case KEYUP:
		return (*KeyUpEvent) (unsafe.Pointer(cevent))
	case TEXTEDITING:
		return (*TextEditingEvent) (unsafe.Pointer(cevent))
	case TEXTINPUT:
		return (*TextInputEvent) (unsafe.Pointer(cevent))
	case MOUSEMOTION:
		return (*MouseMotionEvent) (unsafe.Pointer(cevent))
	case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
		return (*MouseButtonEvent) (unsafe.Pointer(cevent))
	case MOUSEWHEEL:
		return (*MouseWheelEvent) (unsafe.Pointer(cevent))
	case JOYAXISMOTION:
		return (*JoyAxisEvent) (unsafe.Pointer(cevent))
	case JOYBALLMOTION:
		return (*JoyBallEvent) (unsafe.Pointer(cevent))
	case JOYHATMOTION:
		return (*JoyHatEvent) (unsafe.Pointer(cevent))
	case JOYBUTTONDOWN, JOYBUTTONUP:
		return (*JoyButtonEvent) (unsafe.Pointer(cevent))
	case JOYDEVICEADDED, JOYDEVICEREMOVED:
		return (*JoyDeviceEvent) (unsafe.Pointer(cevent))
	case CONTROLLERAXISMOTION:
		return (*ControllerAxisEvent) (unsafe.Pointer(cevent))
	case CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP:
		return (*ControllerButtonEvent) (unsafe.Pointer(cevent))
	case CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED, CONTROLLERDEVICEREMAPPED:
		return (*ControllerDeviceEvent) (unsafe.Pointer(cevent))
	case FINGERDOWN, FINGERUP, FINGERMOTION:
		return (*TouchFingerEvent) (unsafe.Pointer(cevent))
	case DOLLARGESTURE, DOLLARRECORD:
		return (*DollarGestureEvent) (unsafe.Pointer(cevent))
	case MULTIGESTURE:
		return (*MultiGestureEvent) (unsafe.Pointer(cevent))
	case DROPFILE:
		return (*DropEvent) (unsafe.Pointer(cevent))
	case QUIT:
		return (*QuitEvent) (unsafe.Pointer(cevent))
	case USEREVENT:
		return (*UserEvent) (unsafe.Pointer(cevent))
	case CLIPBOARDUPDATE:
		return (*ClipboardEvent) (unsafe.Pointer(cevent))
	}

	panic(fmt.Errorf("Unknown event type: %v", cevent.Type))
}

func cEvent(event Event) *CEvent {
	evv := reflect.ValueOf(event)
	return (*CEvent) (unsafe.Pointer(evv.UnsafeAddr()))
}

func WaitEventTimeout(timeout int) Event {
	var cevent = new(CEvent)
	_timeout := (C.int) (timeout)
	ok := (int) (C.SDL_WaitEventTimeout((*C.SDL_Event)(unsafe.Pointer(cevent)), _timeout))
	if ok == 0 {
		return nil
	}
	return goEvent(cevent)
}

func WaitEvent() Event {
	var cevent = new(CEvent)
	ok := (int) (C.SDL_WaitEvent((*C.SDL_Event)(unsafe.Pointer(cevent))))
	if ok == 0 {
		return nil
	}
	return goEvent(cevent)
}

func PushEvent(event *Event) bool {
	_event := cEvent(event)
	return C.SDL_PushEvent((*C.SDL_Event)(unsafe.Pointer(_event))) == 1
}

/* TODO: implement SDL_EventFilter functions */

func EventState(type_ uint32, state int) uint8 {
	_type := (C.Uint32) (type_)
	_state := (C.int) (state)
	return (uint8) (C.SDL_EventState(_type, _state))
}

func GetEventState(type_ uint32) uint8 {
	_type := (C.Uint32) (type_)
	return (uint8) (C.SDL_EventState(_type, QUERY))
}

func RegisterEvents(numevents int) uint32 {
	_numevents := (C.int) (numevents)
	return (uint32) (C.SDL_RegisterEvents(_numevents))
}
<|endoftext|>