<commit_before>package goutils

import (
	"sort"
)

func DedupStrings(slice []string) []string {
	m := map[string]bool{}
	for _, i := range slice {
		m[i] = true
	}

	ret := make([]string, len(m))
	i := 0
	for v, _ := range m {
		ret[i] = v
		i++
	}

	return ret
}

type StringIntPair struct {
	Key   string
	Value int
}

type OrderByValue []StringIntPair

func (slice OrderByValue) Less(i, j int) bool {
	return slice[i].Value < slice[j].Value
}

func (slice OrderByValue) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (slice OrderByValue) Len() int {
	return len(slice)
}

func IterStringIntMap(in map[string]int) []StringIntPair {
	keys := make([]string, len(in))
	i := 0
	for key, _ := range in {
		keys[i] = key
		i++
	}

	sort.Strings(keys)
	ret := make([]StringIntPair, len(keys))
	i = 0
	for _, key := range keys {
		ret[i] = StringIntPair{key, in[key]}
		i++
	}
	return ret
}
<commit_msg>Add helper to generate trivial mask(filter) array from string slice.<commit_after>package goutils

import (
	"sort"
)

func DedupStrings(slice []string) []string {
	m := map[string]bool{}
	for _, i := range slice {
		m[i] = true
	}

	ret := make([]string, len(m))
	i := 0
	for v, _ := range m {
		ret[i] = v
		i++
	}

	return ret
}

type StringIntPair struct {
	Key   string
	Value int
}

type OrderByValue []StringIntPair

func (slice OrderByValue) Less(i, j int) bool {
	return slice[i].Value < slice[j].Value
}

func (slice OrderByValue) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (slice OrderByValue) Len() int {
	return len(slice)
}

func IterStringIntMap(in map[string]int) []StringIntPair {
	keys := make([]string, len(in))
	i := 0
	for key, _ := range in {
		keys[i] = key
		i++
	}

	sort.Strings(keys)
	ret := make([]StringIntPair, len(keys))
	i = 0
	for _, key := range keys {
		ret[i] = StringIntPair{key, in[key]}
		i++
	}
	return ret
}

func GenMask(slice []string) map[string]bool {
	ret := map[string]bool{}
	for _, i := range slice {
		ret[i] = true
	}
	return ret
}
<|endoftext|>


<commit_before>package apid

import (
	"fmt"
	"os"
)

const (
	SystemEventsSelector EventSelector = "system event"
)

var (
	APIDInitializedEvent = systemEvent{"apid initialized"}
	APIListeningEvent    = systemEvent{"api listening"}

	pluginInitFuncs []PluginInitFunc
	services        Services
)

type Services interface {
	API() APIService
	Config() ConfigService
	Data() DataService
	Events() EventsService
	Log() LogService
}

type PluginInitFunc func(Services) (PluginData, error)

// passed Services can be a factory - makes copies and maintains returned references
// eg. apid.Initialize(factory.DefaultServicesFactory())

func Initialize(s Services) {
	ss := &servicesSet{}
	services = ss
	// order is important
	ss.config = s.Config()

	// ensure storage path exists
	lsp := ss.config.GetString("local_storage_path")
	if err := os.MkdirAll(lsp, 0700); err != nil {
		ss.log.Panicf("can't create local storage path %s:%v", lsp, err)
	}

	ss.log = s.Log()
	ss.events = s.Events()
	ss.api = s.API()
	ss.data = s.Data()

	ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}

func RegisterPlugin(plugin PluginInitFunc) {
	fmt.Printf("Registered plugin: %v\n", plugin)
	pluginInitFuncs = append(pluginInitFuncs, plugin)
}

func InitializePlugins() {
	log := Log()
	log.Debugf("Initializing plugins...")
	pie := PluginsInitializedEvent{
		Description: "plugins initialized",
	}
	for _, pif := range pluginInitFuncs {
		pluginData, err := pif(services)
		if err != nil {
			log.Panicf("Error initializing plugin: %s", err)
		}
		pie.Plugins = append(pie.Plugins, pluginData)
	}
	Events().Emit(SystemEventsSelector, pie)
	pluginInitFuncs = nil
	log.Debugf("done initializing plugins")
}

func AllServices() Services {
	return services
}

func Log() LogService {
	return services.Log()
}

func API() APIService {
	return services.API()
}

func Config() ConfigService {
	return services.Config()
}

func Data() DataService {
	return services.Data()
}

func Events() EventsService {
	return services.Events()
}

type servicesSet struct {
	config ConfigService
	log    LogService
	api    APIService
	data   DataService
	events EventsService
}

func (s *servicesSet) API() APIService {
	return s.api
}

func (s *servicesSet) Config() ConfigService {
	return s.config
}

func (s *servicesSet) Data() DataService {
	return s.data
}

func (s *servicesSet) Events() EventsService {
	return s.events
}

func (s *servicesSet) Log() LogService {
	return s.log
}

type systemEvent struct {
	description string
}
<commit_msg>fix order<commit_after>package apid

import (
	"fmt"
	"os"
)

const (
	SystemEventsSelector EventSelector = "system event"
)

var (
	APIDInitializedEvent = systemEvent{"apid initialized"}
	APIListeningEvent    = systemEvent{"api listening"}

	pluginInitFuncs []PluginInitFunc
	services        Services
)

type Services interface {
	API() APIService
	Config() ConfigService
	Data() DataService
	Events() EventsService
	Log() LogService
}

type PluginInitFunc func(Services) (PluginData, error)

// passed Services can be a factory - makes copies and maintains returned references
// eg. apid.Initialize(factory.DefaultServicesFactory())

func Initialize(s Services) {
	ss := &servicesSet{}
	services = ss
	// order is important
	ss.config = s.Config()
	ss.log = s.Log()

	// ensure storage path exists
	lsp := ss.config.GetString("local_storage_path")
	if err := os.MkdirAll(lsp, 0700); err != nil {
		ss.log.Panicf("can't create local storage path %s: %v", lsp, err)
	}

	ss.events = s.Events()
	ss.api = s.API()
	ss.data = s.Data()

	ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}

func RegisterPlugin(plugin PluginInitFunc) {
	fmt.Printf("Registered plugin: %v\n", plugin)
	pluginInitFuncs = append(pluginInitFuncs, plugin)
}

func InitializePlugins() {
	log := Log()
	log.Debugf("Initializing plugins...")
	pie := PluginsInitializedEvent{
		Description: "plugins initialized",
	}
	for _, pif := range pluginInitFuncs {
		pluginData, err := pif(services)
		if err != nil {
			log.Panicf("Error initializing plugin: %s", err)
		}
		pie.Plugins = append(pie.Plugins, pluginData)
	}
	Events().Emit(SystemEventsSelector, pie)
	pluginInitFuncs = nil
	log.Debugf("done initializing plugins")
}

func AllServices() Services {
	return services
}

func Log() LogService {
	return services.Log()
}

func API() APIService {
	return services.API()
}

func Config() ConfigService {
	return services.Config()
}

func Data() DataService {
	return services.Data()
}

func Events() EventsService {
	return services.Events()
}

type servicesSet struct {
	config ConfigService
	log    LogService
	api    APIService
	data   DataService
	events EventsService
}

func (s *servicesSet) API() APIService {
	return s.api
}

func (s *servicesSet) Config() ConfigService {
	return s.config
}

func (s *servicesSet) Data() DataService {
	return s.data
}

func (s *servicesSet) Events() EventsService {
	return s.events
}

func (s *servicesSet) Log() LogService {
	return s.log
}

type systemEvent struct {
	description string
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Nan Deng
 *
 * 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 pushsrv

import (
	"bytes"
	"crypto/tls"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	. "github.com/uniqush/pushsys"
	"io"
	"net"
	"strconv"
	"sync/atomic"
	"sync"
	"time"
)

type pushRequest struct {
	dp *DeliveryPoint
	notif *Notification
	mid uint32
	resChan chan<- *PushResult
}

type apnsPushService struct {
	nextid uint32
	conns  map[string]net.Conn
	connLock *sync.Mutex

	connChan map[string]chan *pushRequest
	chanLock *sync.Mutex
}

func InstallAPNS() {
	GetPushServiceManager().RegisterPushServiceType(newAPNSPushService())
}

func newAPNSPushService() *apnsPushService {
	ret := new(apnsPushService)
	ret.conns = make(map[string]net.Conn, 5)
	ret.connChan = make(map[string]chan *pushRequest, 5)
	ret.chanLock = new(sync.Mutex)
	ret.connLock= new(sync.Mutex)
	return ret
}

func (p *apnsPushService) Name() string {
	return "apns"
}

func (p *apnsPushService) Finalize() {
	for _, c := range p.conns {
		c.Close()
	}
}
func (p *apnsPushService) BuildPushServiceProviderFromMap(kv map[string]string, psp *PushServiceProvider) error {
	if service, ok := kv["service"]; ok {
		psp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}

	if cert, ok := kv["cert"]; ok && len(cert) > 0 {
		psp.FixedData["cert"] = cert
	} else {
		return errors.New("NoCertificate")
	}

	if key, ok := kv["key"]; ok && len(key) > 0 {
		psp.FixedData["key"] = key
	} else {
		return errors.New("NoPrivateKey")
	}

	if sandbox, ok := kv["sandbox"]; ok {
		if sandbox == "true" {
			psp.VolatileData["addr"] = "gateway.sandbox.push.apple.com:2195"
			return nil
		}
	}
	psp.VolatileData["addr"] = "gateway.push.apple.com:2195"
	return nil
}

func (p *apnsPushService) BuildDeliveryPointFromMap(kv map[string]string, dp *DeliveryPoint) error {
	if service, ok := kv["service"]; ok && len(service) > 0 {
		dp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}
	if sub, ok := kv["subscriber"]; ok && len(sub) > 0 {
		dp.FixedData["subscriber"] = sub
	} else {
		return errors.New("NoSubscriber")
	}
	if devtoken, ok := kv["devtoken"]; ok && len(devtoken) > 0 {
		dp.FixedData["devtoken"] = devtoken
	} else {
		return errors.New("NoDevToken")
	}
	return nil
}

func toAPNSPayload(n *Notification) ([]byte, error) {
	payload := make(map[string]interface{})
	aps := make(map[string]interface{})
	alert := make(map[string]interface{})
	for k, v := range n.Data {
		switch k {
		case "msg":
			alert["body"] = v
		case "badge":
			b, err := strconv.Atoi(v)
			if err != nil {
				continue
			} else {
				aps["badge"] = b
			}
		case "sound":
			aps["sound"] = v
		case "img":
			alert["launch-image"] = v
		case "id":
			continue
		case "expiry":
			continue
		default:
			payload[k] = v
		}
	}
	aps["alert"] = alert
	payload["aps"] = aps
	j, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}
	return j, nil
}

func writen(w io.Writer, buf []byte) error {
	n := len(buf)
	for n >= 0 {
		l, err := w.Write(buf)
		if err != nil {
			return err
		}
		if l >= n {
			return nil
		}
		n -= l
		buf = buf[l:]
	}
	return nil
}

func (p *apnsPushService) getConn(psp *PushServiceProvider) (net.Conn, error) {
	name := psp.Name()
	if conn, ok := p.conns[name]; ok {
		return conn, nil
	}
	return p.reconnect(psp)
}

func (p *apnsPushService) reconnect(psp *PushServiceProvider) (net.Conn, error) {
	name := psp.Name()
	p.connLock.Lock()
	defer p.connLock.Unlock()

	if conn, ok := p.conns[name]; ok {
		conn.Close()
	}
	cert, err := tls.LoadX509KeyPair(psp.FixedData["cert"], psp.FixedData["key"])
	if err != nil {
		return nil, NewBadPushServiceProviderWithDetails(psp, err.Error())
	}
	conf := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		InsecureSkipVerify: true,
	}
	tlsconn, err := tls.Dial("tcp", psp.VolatileData["addr"], conf)
	if err != nil {
		return nil, NewConnectionError(err)
	}
	err = tlsconn.Handshake()
	if err != nil {
		return nil, NewConnectionError(err)
	}
	p.conns[name] = tlsconn
	return tlsconn, nil
}

func (self *apnsPushService) getRequestChannel(psp *PushServiceProvider) chan *pushRequest{
	var ch chan *pushRequest
	var ok bool
	self.chanLock.Lock()
	if ch, ok = self.connChan[psp.Name()]; !ok {
		ch = make(chan *pushRequest)
		self.connChan[psp.Name()] = ch
		go self.pushWorker(psp, ch)
	}
	self.chanLock.Unlock()
	return ch
}

type apnsResult struct {
	msgId uint32
	status uint8
	err error
}

func (self *apnsPushService) Push(psp *PushServiceProvider, dpQueue <-chan *DeliveryPoint, resQueue chan<- *PushResult, notif *Notification) {
	/* First, get the request channel */
	ch := self.getRequestChannel(psp)

	for dp := range dpQueue {
		go func () {
			resultChannel := make(chan *PushResult, 1)
			req := new(pushRequest)
			req.dp = dp
			req.notif = notif
			req.resChan = resultChannel
			req.mid = atomic.AddUint32(&(self.nextid), 1)

			ch<-req

			for {
				select {
				case res := <-resultChannel:
					resQueue <- res
				case <-time.After(5 * time.Second):
					return

				}
			}

		}()
	}
}

func (self *apnsPushService) resultCollector(psp *PushServiceProvider, resChan chan<- *apnsResult) {
	c, err := self.getConn(psp)
	if err != nil {
		res := new(apnsResult)
		res.err = NewConnectionError(err)
		resChan<-res
		return
	}

	for {
		readb := make([]byte, 6)
		nr, err := c.Read(readb[:])
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}
		if nr != 6 {
			res := new(apnsResult)
			res.err = NewConnectionError(fmt.Errorf("[APNS] Received %v bytes", nr))
			resChan<-res
			continue
		}

		buf := bytes.NewBuffer(readb)
		var cmd uint8
		var status uint8
		var msgid uint32

		err = binary.Read(buf, binary.BigEndian, &cmd)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		err = binary.Read(buf, binary.BigEndian, &status)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		err = binary.Read(buf, binary.BigEndian, &msgid)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		res := new(apnsResult)
		res.msgId = msgid
		res.status = status
		resChan<-res
	}
}

func (self *apnsPushService) singlePush(psp *PushServiceProvider, dp *DeliveryPoint, notif *Notification, mid uint32) error {
	devtoken := dp.FixedData["devtoken"]

	btoken, err := hex.DecodeString(devtoken)
	if err != nil {
		return NewBadDeliveryPointWithDetails(dp, err.Error())
	}

	bpayload, err := toAPNSPayload(notif)
	if err != nil {
		return NewBadNotificationWithDetails(err.Error())
	}

	buffer := bytes.NewBuffer([]byte{})

	// command
	binary.Write(buffer, binary.BigEndian, uint8(1))

	// transaction id
	binary.Write(buffer, binary.BigEndian, mid)

	// TODO Expiry
	expiry := uint32(time.Now().Second() + 60*60)
	binary.Write(buffer, binary.BigEndian, expiry)

	// device token
	binary.Write(buffer, binary.BigEndian, uint16(len(btoken)))
	binary.Write(buffer, binary.BigEndian, btoken)

	// payload
	binary.Write(buffer, binary.BigEndian, uint16(len(bpayload)))
	binary.Write(buffer, binary.BigEndian, bpayload)
	pdu := buffer.Bytes()

	tlsconn, err := self.getConn(psp)
	if err != nil {
		return NewConnectionError(err)
	}

	for i := 0; i < 2; i++ {
		err = writen(tlsconn, pdu)
		if err != nil {
			tlsconn, err = self.reconnect(psp)
			if err != nil {
				return NewConnectionError(err)
			}
		} else {
			break
		}
	}
	if err != nil {
		return NewConnectionError(err)
	}

	return nil
}

func (self *apnsPushService) pushWorker(psp *PushServiceProvider, reqChan chan *pushRequest) {
	resChan := make(chan *apnsResult)

	reqIdMap := make(map[uint32]*pushRequest)

	var connErr error

	connErr = nil

	go self.resultCollector(psp, resChan)
	for {
		select {
		case req := <-reqChan:
			dp := req.dp
			notif := req.notif
			mid := req.mid

			if connErr != nil {
				result := new(PushResult)
				result.Content = notif
				result.Provider = psp
				result.Destination = dp
				result.MsgId = fmt.Sprintf("%v", mid)
				result.Err = connErr
				req.resChan<-result
				continue
			}

			reqIdMap[mid] = req
			err := self.singlePush(psp, dp, notif, mid)

			if err != nil {
				result := new(PushResult)
				result.Content = notif
				result.Provider = psp
				result.Destination = dp
				result.MsgId = fmt.Sprintf("apns:%v-%v", psp.Name(), mid)
				result.Err = err
				req.resChan<-result
				delete(reqIdMap, mid)
			}

		case apnsres := <-resChan:
			if cerr, ok := apnsres.err.(*ConnectionError); ok {
				connErr = cerr
			}

			if req, ok := reqIdMap[apnsres.msgId]; ok {
				result := new(PushResult)
				result.Content = req.notif
				result.Provider = psp
				result.Destination = req.dp
				result.MsgId = fmt.Sprintf("%v", apnsres.msgId)
				if apnsres.err != nil {
					result := new(PushResult)
					result.Err = apnsres.err
					req.resChan<-result
				}

				switch apnsres.status {
				case 0:
					result.Err = nil
				case 1:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Processing Error")
				case 2:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Missing Device Token")
				case 3:
					result.Err = NewBadNotificationWithDetails("Missing topic")
				case 4:
					result.Err = NewBadNotificationWithDetails("Missing payload")
				case 5:
					result.Err = NewBadNotificationWithDetails("Invalid token size")
				case 6:
					result.Err = NewBadNotificationWithDetails("Invalid topic size")
				case 7:
					result.Err = NewBadNotificationWithDetails("Invalid payload size")
				case 8:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Invalid Token")
				default:
					result.Err = fmt.Errorf("Unknown Error: %d", apnsres.status)
				}

				req.resChan<-result
				close(req.resChan)
				delete(reqIdMap, apnsres.msgId)
			}
		}
	}
}

<commit_msg>Push can only return when all message has pushed(or failed)<commit_after>/*
 * Copyright 2011 Nan Deng
 *
 * 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 pushsrv

import (
	"bytes"
	"crypto/tls"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	. "github.com/uniqush/pushsys"
	"io"
	"net"
	"strconv"
	"sync/atomic"
	"sync"
	"time"
)

type pushRequest struct {
	dp *DeliveryPoint
	notif *Notification
	mid uint32
	resChan chan<- *PushResult
}

type apnsPushService struct {
	nextid uint32
	conns  map[string]net.Conn
	connLock *sync.Mutex

	connChan map[string]chan *pushRequest
	chanLock *sync.Mutex
}

func InstallAPNS() {
	GetPushServiceManager().RegisterPushServiceType(newAPNSPushService())
}

func newAPNSPushService() *apnsPushService {
	ret := new(apnsPushService)
	ret.conns = make(map[string]net.Conn, 5)
	ret.connChan = make(map[string]chan *pushRequest, 5)
	ret.chanLock = new(sync.Mutex)
	ret.connLock= new(sync.Mutex)
	return ret
}

func (p *apnsPushService) Name() string {
	return "apns"
}

func (p *apnsPushService) Finalize() {
	for _, c := range p.conns {
		c.Close()
	}
}
func (p *apnsPushService) BuildPushServiceProviderFromMap(kv map[string]string, psp *PushServiceProvider) error {
	if service, ok := kv["service"]; ok {
		psp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}

	if cert, ok := kv["cert"]; ok && len(cert) > 0 {
		psp.FixedData["cert"] = cert
	} else {
		return errors.New("NoCertificate")
	}

	if key, ok := kv["key"]; ok && len(key) > 0 {
		psp.FixedData["key"] = key
	} else {
		return errors.New("NoPrivateKey")
	}

	if sandbox, ok := kv["sandbox"]; ok {
		if sandbox == "true" {
			psp.VolatileData["addr"] = "gateway.sandbox.push.apple.com:2195"
			return nil
		}
	}
	psp.VolatileData["addr"] = "gateway.push.apple.com:2195"
	return nil
}

func (p *apnsPushService) BuildDeliveryPointFromMap(kv map[string]string, dp *DeliveryPoint) error {
	if service, ok := kv["service"]; ok && len(service) > 0 {
		dp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}
	if sub, ok := kv["subscriber"]; ok && len(sub) > 0 {
		dp.FixedData["subscriber"] = sub
	} else {
		return errors.New("NoSubscriber")
	}
	if devtoken, ok := kv["devtoken"]; ok && len(devtoken) > 0 {
		dp.FixedData["devtoken"] = devtoken
	} else {
		return errors.New("NoDevToken")
	}
	return nil
}

func toAPNSPayload(n *Notification) ([]byte, error) {
	payload := make(map[string]interface{})
	aps := make(map[string]interface{})
	alert := make(map[string]interface{})
	for k, v := range n.Data {
		switch k {
		case "msg":
			alert["body"] = v
		case "badge":
			b, err := strconv.Atoi(v)
			if err != nil {
				continue
			} else {
				aps["badge"] = b
			}
		case "sound":
			aps["sound"] = v
		case "img":
			alert["launch-image"] = v
		case "id":
			continue
		case "expiry":
			continue
		default:
			payload[k] = v
		}
	}
	aps["alert"] = alert
	payload["aps"] = aps
	j, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}
	return j, nil
}

func writen(w io.Writer, buf []byte) error {
	n := len(buf)
	for n >= 0 {
		l, err := w.Write(buf)
		if err != nil {
			return err
		}
		if l >= n {
			return nil
		}
		n -= l
		buf = buf[l:]
	}
	return nil
}

func (p *apnsPushService) getConn(psp *PushServiceProvider) (net.Conn, error) {
	name := psp.Name()
	if conn, ok := p.conns[name]; ok {
		return conn, nil
	}
	return p.reconnect(psp)
}

func (p *apnsPushService) reconnect(psp *PushServiceProvider) (net.Conn, error) {
	name := psp.Name()
	p.connLock.Lock()
	defer p.connLock.Unlock()

	if conn, ok := p.conns[name]; ok {
		conn.Close()
	}
	cert, err := tls.LoadX509KeyPair(psp.FixedData["cert"], psp.FixedData["key"])
	if err != nil {
		return nil, NewBadPushServiceProviderWithDetails(psp, err.Error())
	}
	conf := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		InsecureSkipVerify: true,
	}
	tlsconn, err := tls.Dial("tcp", psp.VolatileData["addr"], conf)
	if err != nil {
		return nil, NewConnectionError(err)
	}
	err = tlsconn.Handshake()
	if err != nil {
		return nil, NewConnectionError(err)
	}
	p.conns[name] = tlsconn
	return tlsconn, nil
}

func (self *apnsPushService) getRequestChannel(psp *PushServiceProvider) chan *pushRequest{
	var ch chan *pushRequest
	var ok bool
	self.chanLock.Lock()
	if ch, ok = self.connChan[psp.Name()]; !ok {
		ch = make(chan *pushRequest)
		self.connChan[psp.Name()] = ch
		go self.pushWorker(psp, ch)
	}
	self.chanLock.Unlock()
	return ch
}

type apnsResult struct {
	msgId uint32
	status uint8
	err error
}

func (self *apnsPushService) Push(psp *PushServiceProvider, dpQueue <-chan *DeliveryPoint, resQueue chan<- *PushResult, notif *Notification) {
	/* First, get the request channel */
	ch := self.getRequestChannel(psp)

	wg := new(sync.WaitGroup)

	for dp := range dpQueue {
		wg.Add(1)
		go func () {
			resultChannel := make(chan *PushResult, 1)
			req := new(pushRequest)
			req.dp = dp
			req.notif = notif
			req.resChan = resultChannel
			req.mid = atomic.AddUint32(&(self.nextid), 1)

			ch<-req

			for {
				select {
				case res := <-resultChannel:
					resQueue <- res
				case <-time.After(5 * time.Second):
					return

				}
			}
			wg.Done()

		}()
	}

	wg.Wait()
}

func (self *apnsPushService) resultCollector(psp *PushServiceProvider, resChan chan<- *apnsResult) {
	c, err := self.getConn(psp)
	if err != nil {
		res := new(apnsResult)
		res.err = NewConnectionError(err)
		resChan<-res
		return
	}

	for {
		var cmd uint8
		var status uint8
		var msgid uint32

		err = binary.Read(c, binary.BigEndian, &cmd)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		err = binary.Read(c, binary.BigEndian, &status)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		err = binary.Read(c, binary.BigEndian, &msgid)
		if err != nil {
			res := new(apnsResult)
			res.err = NewConnectionError(err)
			resChan<-res
			continue
		}

		res := new(apnsResult)
		res.msgId = msgid
		res.status = status
		resChan<-res
	}
}

func (self *apnsPushService) singlePush(psp *PushServiceProvider, dp *DeliveryPoint, notif *Notification, mid uint32) error {
	devtoken := dp.FixedData["devtoken"]

	btoken, err := hex.DecodeString(devtoken)
	if err != nil {
		return NewBadDeliveryPointWithDetails(dp, err.Error())
	}

	bpayload, err := toAPNSPayload(notif)
	if err != nil {
		return NewBadNotificationWithDetails(err.Error())
	}

	buffer := bytes.NewBuffer([]byte{})

	// command
	binary.Write(buffer, binary.BigEndian, uint8(1))

	// transaction id
	binary.Write(buffer, binary.BigEndian, mid)

	// TODO Expiry
	expiry := uint32(time.Now().Second() + 60*60)
	binary.Write(buffer, binary.BigEndian, expiry)

	// device token
	binary.Write(buffer, binary.BigEndian, uint16(len(btoken)))
	binary.Write(buffer, binary.BigEndian, btoken)

	// payload
	binary.Write(buffer, binary.BigEndian, uint16(len(bpayload)))
	binary.Write(buffer, binary.BigEndian, bpayload)
	pdu := buffer.Bytes()

	tlsconn, err := self.getConn(psp)
	if err != nil {
		return NewConnectionError(err)
	}

	for i := 0; i < 2; i++ {
		err = writen(tlsconn, pdu)
		if err != nil {
			tlsconn, err = self.reconnect(psp)
			if err != nil {
				return NewConnectionError(err)
			}
		} else {
			break
		}
	}
	if err != nil {
		return NewConnectionError(err)
	}

	return nil
}

func (self *apnsPushService) pushWorker(psp *PushServiceProvider, reqChan chan *pushRequest) {
	resChan := make(chan *apnsResult)

	reqIdMap := make(map[uint32]*pushRequest)

	var connErr error

	connErr = nil

	go self.resultCollector(psp, resChan)
	for {
		select {
		case req := <-reqChan:
			dp := req.dp
			notif := req.notif
			mid := req.mid

			if connErr != nil {
				result := new(PushResult)
				result.Content = notif
				result.Provider = psp
				result.Destination = dp
				result.MsgId = fmt.Sprintf("%v", mid)
				result.Err = connErr
				req.resChan<-result
				continue
			}

			reqIdMap[mid] = req
			err := self.singlePush(psp, dp, notif, mid)

			if err != nil {
				result := new(PushResult)
				result.Content = notif
				result.Provider = psp
				result.Destination = dp
				result.MsgId = fmt.Sprintf("apns:%v-%v", psp.Name(), mid)
				result.Err = err
				req.resChan<-result
				delete(reqIdMap, mid)
			}

		case apnsres := <-resChan:
			if cerr, ok := apnsres.err.(*ConnectionError); ok {
				connErr = cerr
			}

			if req, ok := reqIdMap[apnsres.msgId]; ok {
				result := new(PushResult)
				result.Content = req.notif
				result.Provider = psp
				result.Destination = req.dp
				result.MsgId = fmt.Sprintf("apns:%v-%v", psp.Name(), apnsres.msgId)
				if apnsres.err != nil {
					result := new(PushResult)
					result.Err = apnsres.err
					req.resChan<-result
					continue
				}

				switch apnsres.status {
				case 0:
					result.Err = nil
				case 1:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Processing Error")
				case 2:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Missing Device Token")
				case 3:
					result.Err = NewBadNotificationWithDetails("Missing topic")
				case 4:
					result.Err = NewBadNotificationWithDetails("Missing payload")
				case 5:
					result.Err = NewBadNotificationWithDetails("Invalid token size")
				case 6:
					result.Err = NewBadNotificationWithDetails("Invalid topic size")
				case 7:
					result.Err = NewBadNotificationWithDetails("Invalid payload size")
				case 8:
					result.Err = NewBadDeliveryPointWithDetails(req.dp, "Invalid Token")
				default:
					result.Err = fmt.Errorf("Unknown Error: %d", apnsres.status)
				}

				req.resChan<-result
				close(req.resChan)
				delete(reqIdMap, apnsres.msgId)
			}
		}
	}
}

<|endoftext|>


<commit_before>// Copyright 2010 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"
	"encoding/json"
	"net/http"
	"log"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"strings"
)

type AccessToken struct {
 	Token  string
 	Expiry int64
}

func googleOAuth2Config(domain string) *oauth2.Config {
	appConf := configuration()
	conf := &oauth2.Config{
 		ClientID:     appConf.GoogleClientID,
		ClientSecret: appConf.GoogleClientSecret,
 		RedirectURL:  "postmessage",
		Scopes:       []string{"https://www.googleapis.com/auth/plus.profile.emails.read"},
		Endpoint: google.Endpoint,
 	}
	return conf
}

func readHttpBody(response *http.Response) string {
	fmt.Println("Reading body")
 	bodyBuffer := make([]byte, 5000)
 	var str string
 	count, err := response.Body.Read(bodyBuffer)
 	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
 		if err != nil {

 		}
 		str += string(bodyBuffer[:count])
 	}
 	return str
 }

func oauth2callback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	newAccount := r.FormValue("new_account")
 	conf := googleOAuth2Config(domain(r))
	tok, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		log.Fatal(err)
	}
	client := conf.Client(oauth2.NoContext, tok)
 	response, err := client.Get("https://www.googleapis.com/plus/v1/people/me")
 	// handle err. You need to change this into something more robust
 	// such as redirect back to home page with error message
 	if err != nil {
 		w.Write([]byte(err.Error()))
 	}
 	str := readHttpBody(response)
	type Email struct {
		Value string
		Type string
	}
	type OAuth2Response struct {
		Kind string
		Emails []Email
	}
	dec := json.NewDecoder(strings.NewReader(str))
	var m OAuth2Response
	if err := dec.Decode(&m); err != nil {
		log.Fatal(err)
	}
	for _, v := range m.Emails {
		fmt.Println("email (value, type): " + v.Value + ", " + v.Type)
	}
	email := m.Emails[0].Value
	if newAccount == "true" {
		fmt.Println("NEW ACCOUNT")
		dbCreate(email)
		dbInsert(email, "#1")
	}
	w.Write([]byte(email))
}

<commit_msg>Add debug println in oauth2callback<commit_after>// Copyright 2010 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"
	"encoding/json"
	"net/http"
	"log"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"strings"
)

type AccessToken struct {
 	Token  string
 	Expiry int64
}

func googleOAuth2Config(domain string) *oauth2.Config {
	appConf := configuration()
	conf := &oauth2.Config{
 		ClientID:     appConf.GoogleClientID,
		ClientSecret: appConf.GoogleClientSecret,
 		RedirectURL:  "postmessage",
		Scopes:       []string{"https://www.googleapis.com/auth/plus.profile.emails.read"},
		Endpoint: google.Endpoint,
 	}
	return conf
}

func readHttpBody(response *http.Response) string {
	fmt.Println("Reading body")
 	bodyBuffer := make([]byte, 5000)
 	var str string
 	count, err := response.Body.Read(bodyBuffer)
 	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
 		if err != nil {

 		}
 		str += string(bodyBuffer[:count])
 	}
 	return str
 }

func oauth2callback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	fmt.Println("oauth2callback - code: " + code)
	newAccount := r.FormValue("new_account")
 	conf := googleOAuth2Config(domain(r))
	tok, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		log.Fatal(err)
	}
	client := conf.Client(oauth2.NoContext, tok)
 	response, err := client.Get("https://www.googleapis.com/plus/v1/people/me")
 	// handle err. You need to change this into something more robust
 	// such as redirect back to home page with error message
 	if err != nil {
 		w.Write([]byte(err.Error()))
 	}
 	str := readHttpBody(response)
	type Email struct {
		Value string
		Type string
	}
	type OAuth2Response struct {
		Kind string
		Emails []Email
	}
	dec := json.NewDecoder(strings.NewReader(str))
	var m OAuth2Response
	if err := dec.Decode(&m); err != nil {
		log.Fatal(err)
	}
	for _, v := range m.Emails {
		fmt.Println("email (value, type): " + v.Value + ", " + v.Type)
	}
	email := m.Emails[0].Value
	if newAccount == "true" {
		fmt.Println("NEW ACCOUNT")
		dbCreate(email)
		dbInsert(email, "#1")
	}
	w.Write([]byte(email))
}

<|endoftext|>


<commit_before>/*
Package ble provides functions to discover, connect, pair,
and communicate with Bluetooth Low Energy peripheral devices.

This implementation uses the BlueZ D-Bus interface, rather than sockets.
It is similar to github.com/adafruit/Adafruit_Python_BluefruitLE
*/
package ble

import (
	"fmt"
	"io"
	"time"

	"github.com/godbus/dbus"
)

const (
	objectManager = "org.freedesktop.DBus.ObjectManager"
)

// Connection represents a D-Bus connection.
type Connection struct {
	bus *dbus.Conn

	// It would be nice to factor out the subtypes here,
	// but then the reflection used by dbus.Store() wouldn't work.
	objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
}

// Open opens a connection to the system D-Bus
func Open() (*Connection, error) {
	bus, err := dbus.SystemBus()
	if err != nil {
		return nil, err
	}
	conn := Connection{bus: bus}
	err = conn.Update()
	if err != nil {
		conn.Close()
		return nil, err
	}
	return &conn, nil
}

// Close closes the D-Bus connection.
func (conn *Connection) Close() {
	_ = conn.bus.Close()
}

// Update gets all objects and properties.
// See http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
func (conn *Connection) Update() error {
	obj := conn.bus.Object("org.bluez", "/")
	call := obj.Call(dot(objectManager, "GetManagedObjects"), 0)
	return call.Store(&conn.objects)
}

type dbusInterfaces *map[string]map[string]dbus.Variant

// The iterObjects function applies a function of type objectProc to
// each object in the cache.  It should return true if the iteration
// should stop, false if it should continue.
type objectProc func(dbus.ObjectPath, dbusInterfaces) bool

func (conn *Connection) iterObjects(proc objectProc) {
	for path, dict := range conn.objects {
		if proc(path, &dict) {
			return
		}
	}
}

// Print prints the objects in the cache.
func (conn *Connection) Print(w io.Writer) {
	printer := func(path dbus.ObjectPath, dict dbusInterfaces) bool {
		return printObject(w, path, dict)
	}
	conn.iterObjects(printer)
}

func printObject(w io.Writer, path dbus.ObjectPath, dict dbusInterfaces) bool {
	fmt.Fprintln(w, path)
	for iface, props := range *dict {
		printProperties(w, iface, props)
	}
	fmt.Fprintln(w)
	return false
}

// BaseObject is the interface satisfied by bluez D-Bus objects.
type BaseObject interface {
	Conn() *Connection
	Path() dbus.ObjectPath
	Interface() string
	Name() string
	Print(io.Writer)
}

type properties map[string]dbus.Variant

type blob struct {
	conn       *Connection
	path       dbus.ObjectPath
	iface      string
	properties properties
	object     dbus.BusObject
}

// Conn returns the object's D-Bus connection.
func (obj *blob) Conn() *Connection {
	return obj.conn
}

// Path returns the object's D-Bus path.
func (obj *blob) Path() dbus.ObjectPath {
	return obj.path
}

// Interface returns the object's D-Bus interface name.
func (obj *blob) Interface() string {
	return obj.iface
}

// Name returns the object's name.
func (obj *blob) Name() string {
	name, ok := obj.properties["Name"].Value().(string)
	if !ok {
		return string(obj.path)
	}
	return name
}

func (obj *blob) callv(method string, args ...interface{}) *dbus.Call {
	const callTimeout = 5 * time.Second
	c := obj.object.Go(dot(obj.iface, method), 0, nil, args...)
	if c.Err == nil {
		select {
		case <-c.Done:
		case <-time.After(callTimeout):
			c.Err = fmt.Errorf("BLE call timeout")
		}
	}
	return c
}

func (obj *blob) call(method string, args ...interface{}) error {
	return obj.callv(method, args...).Err
}

// Print prints the object.
func (obj *blob) Print(w io.Writer) {
	fmt.Fprintf(w, "%s [%s]\n", obj.path, obj.iface)
	printProperties(w, "", obj.properties)
}

func printProperties(w io.Writer, iface string, props properties) {
	indent := "    "
	if iface != "" {
		fmt.Fprintf(w, "%s%s\n", indent, iface)
		indent += indent
	}
	for key, val := range props {
		fmt.Fprintf(w, "%s%s %s\n", indent, key, val.String())
	}
}

// The findObject function tests each object with functions of type predicate.
type predicate func(*blob) bool

// findObject finds an object satisfying the given predicate.
// If returns an error if zero or more than one is found.
func (conn *Connection) findObject(iface string, matching predicate) (*blob, error) {
	var found []*blob
	conn.iterObjects(func(path dbus.ObjectPath, dict dbusInterfaces) bool {
		props := (*dict)[iface]
		if props == nil {
			return false
		}
		obj := &blob{
			conn:       conn,
			path:       path,
			iface:      iface,
			properties: props,
			object:     conn.bus.Object("org.bluez", path),
		}
		if matching(obj) {
			found = append(found, obj)
		}
		return false
	})
	switch len(found) {
	case 1:
		return found[0], nil
	case 0:
		return nil, fmt.Errorf("interface %s not found", iface)
	default:
		return nil, fmt.Errorf("found %d instances of interface %s", len(found), iface)
	}
}

func dot(a, b string) string {
	return a + "." + b
}
<commit_msg>Use type aliases to factor out dbus subtypes<commit_after>/*
Package ble provides functions to discover, connect, pair,
and communicate with Bluetooth Low Energy peripheral devices.

This implementation uses the BlueZ D-Bus interface, rather than sockets.
It is similar to github.com/adafruit/Adafruit_Python_BluefruitLE
*/
package ble

import (
	"fmt"
	"io"
	"time"

	"github.com/godbus/dbus"
)

const (
	objectManager = "org.freedesktop.DBus.ObjectManager"
)

// Use type aliases for these subtypes so the reflection
// used by dbus.Store() works correctly.

// Object represents a managed D-Bus object.
type Object = map[string]properties

type properties = map[string]dbus.Variant

// Connection represents a D-Bus connection.
type Connection struct {
	bus     *dbus.Conn
	objects map[dbus.ObjectPath]Object
}

// Open opens a connection to the system D-Bus
func Open() (*Connection, error) {
	bus, err := dbus.SystemBus()
	if err != nil {
		return nil, err
	}
	conn := Connection{bus: bus}
	err = conn.Update()
	if err != nil {
		conn.Close()
		return nil, err
	}
	return &conn, nil
}

// Close closes the D-Bus connection.
func (conn *Connection) Close() {
	_ = conn.bus.Close()
}

// Update gets all objects and properties.
// See http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
func (conn *Connection) Update() error {
	obj := conn.bus.Object("org.bluez", "/")
	call := obj.Call(dot(objectManager, "GetManagedObjects"), 0)
	return call.Store(&conn.objects)
}

// The iterObjects function applies a function of type objectProc to
// each object in the cache.  It should return true if the iteration
// should stop, false if it should continue.
type objectProc func(dbus.ObjectPath, Object) bool

func (conn *Connection) iterObjects(proc objectProc) {
	for path, dict := range conn.objects {
		if proc(path, dict) {
			return
		}
	}
}

// Print prints the objects in the cache.
func (conn *Connection) Print(w io.Writer) {
	printer := func(path dbus.ObjectPath, dict Object) bool {
		return printObject(w, path, dict)
	}
	conn.iterObjects(printer)
}

func printObject(w io.Writer, path dbus.ObjectPath, dict Object) bool {
	fmt.Fprintln(w, path)
	for iface, props := range dict {
		printProperties(w, iface, props)
	}
	fmt.Fprintln(w)
	return false
}

// BaseObject is the interface satisfied by bluez D-Bus objects.
type BaseObject interface {
	Conn() *Connection
	Path() dbus.ObjectPath
	Interface() string
	Name() string
	Print(io.Writer)
}

type blob struct {
	conn       *Connection
	path       dbus.ObjectPath
	iface      string
	properties properties
	object     dbus.BusObject
}

// Conn returns the object's D-Bus connection.
func (obj *blob) Conn() *Connection {
	return obj.conn
}

// Path returns the object's D-Bus path.
func (obj *blob) Path() dbus.ObjectPath {
	return obj.path
}

// Interface returns the object's D-Bus interface name.
func (obj *blob) Interface() string {
	return obj.iface
}

// Name returns the object's name.
func (obj *blob) Name() string {
	name, ok := obj.properties["Name"].Value().(string)
	if !ok {
		return string(obj.path)
	}
	return name
}

func (obj *blob) callv(method string, args ...interface{}) *dbus.Call {
	const callTimeout = 5 * time.Second
	c := obj.object.Go(dot(obj.iface, method), 0, nil, args...)
	if c.Err == nil {
		select {
		case <-c.Done:
		case <-time.After(callTimeout):
			c.Err = fmt.Errorf("BLE call timeout")
		}
	}
	return c
}

func (obj *blob) call(method string, args ...interface{}) error {
	return obj.callv(method, args...).Err
}

// Print prints the object.
func (obj *blob) Print(w io.Writer) {
	fmt.Fprintf(w, "%s [%s]\n", obj.path, obj.iface)
	printProperties(w, "", obj.properties)
}

func printProperties(w io.Writer, iface string, props properties) {
	indent := "    "
	if iface != "" {
		fmt.Fprintf(w, "%s%s\n", indent, iface)
		indent += indent
	}
	for key, val := range props {
		fmt.Fprintf(w, "%s%s %s\n", indent, key, val.String())
	}
}

// The findObject function tests each object with functions of type predicate.
type predicate func(*blob) bool

// findObject finds an object satisfying the given predicate.
// If returns an error if zero or more than one is found.
func (conn *Connection) findObject(iface string, matching predicate) (*blob, error) {
	var found []*blob
	conn.iterObjects(func(path dbus.ObjectPath, dict Object) bool {
		props := dict[iface]
		if props == nil {
			return false
		}
		obj := &blob{
			conn:       conn,
			path:       path,
			iface:      iface,
			properties: props,
			object:     conn.bus.Object("org.bluez", path),
		}
		if matching(obj) {
			found = append(found, obj)
		}
		return false
	})
	switch len(found) {
	case 1:
		return found[0], nil
	case 0:
		return nil, fmt.Errorf("interface %s not found", iface)
	default:
		return nil, fmt.Errorf("found %d instances of interface %s", len(found), iface)
	}
}

func dot(a, b string) string {
	return a + "." + b
}
<|endoftext|>


<commit_before>package hood

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

type Base struct {
	Dialect Dialect
}

func (d *Base) NextMarker(pos *int) string {
	m := fmt.Sprintf("$%d", *pos+1)
	*pos++
	return m
}

func (d *Base) Quote(s string) string {
	return fmt.Sprintf(`"%s"`, s)
}

func (d *Base) ParseBool(value reflect.Value) bool {
	return value.Bool()
}

func (d *Base) SetModelValue(driverValue, fieldValue reflect.Value) error {
	switch fieldValue.Type().Kind() {
	case reflect.Bool:
		fieldValue.SetBool(d.Dialect.ParseBool(driverValue.Elem()))
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		fieldValue.SetInt(driverValue.Elem().Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		// reading uint from int value causes panic
		switch driverValue.Elem().Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			fieldValue.SetUint(uint64(driverValue.Elem().Int()))
		default:
			fieldValue.SetUint(driverValue.Elem().Uint())
		}
	case reflect.Float32, reflect.Float64:
		fieldValue.SetFloat(driverValue.Elem().Float())
	case reflect.String:
		fieldValue.SetString(string(driverValue.Elem().Bytes()))
	case reflect.Slice:
		if reflect.TypeOf(driverValue.Interface()).Elem().Kind() == reflect.Uint8 {
			fieldValue.SetBytes(driverValue.Elem().Bytes())
		}
	case reflect.Struct:
		if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
			fieldValue.Set(driverValue.Elem())
		}
	}
	return nil
}

func (d *Base) ConvertHoodType(f interface{}) interface{} {
	if t, ok := f.(Created); ok {
		return t.Time
	}
	if t, ok := f.(Updated); ok {
		return t.Time
	}
	return f
}

func (d *Base) QuerySql(hood *Hood) (string, []interface{}) {
	query := make([]string, 0, 20)
	args := make([]interface{}, 0, 20)
	if hood.selectTable != "" {
		selector := "*"
		if c := hood.selectCols; len(c) > 0 {
			quotedCols := make([]string, 0, len(hood.selectCols))
			for _, c := range hood.selectCols {
				quotedCols = append(quotedCols, d.Dialect.Quote(c))
			}
			selector = strings.Join(quotedCols, ", ")
		}
		query = append(query, fmt.Sprintf("SELECT %v FROM %v", selector, d.Dialect.Quote(hood.selectTable)))
	}
	for i, op := range hood.joinOps {
		joinType := "INNER"
		switch op {
		case LeftJoin:
			joinType = "LEFT"
		case RightJoin:
			joinType = "RIGHT"
		case FullJoin:
			joinType = "FULL"
		}
		query = append(query, fmt.Sprintf(
			"%s JOIN %v ON %s.%s = %s.%s",
			joinType,
			d.Dialect.Quote(tableName(hood.joinTables[i])),
			d.Dialect.Quote(tableName(hood.selectTable)),
			d.Dialect.Quote(hood.joinCol1[i]),
			d.Dialect.Quote(tableName(hood.joinTables[i])),
			d.Dialect.Quote(hood.joinCol2[i]),
		),
		)
	}
	if x := hood.whereClauses; len(x) > 0 {
		query = append(query, fmt.Sprintf("WHERE %v", strings.Join(x, " AND ")))
		args = append(args, hood.whereArgs...)
	}
	if x := hood.groupBy; x != "" {
		query = append(query, fmt.Sprintf("GROUP BY %v", d.Dialect.Quote(x)))
	}
	if x := hood.havingCond; x != "" {
		query = append(query, fmt.Sprintf("HAVING %v", x))
		args = append(args, hood.havingArgs...)
	}
	if x := hood.orderBy; x != "" {
		query = append(query, fmt.Sprintf("ORDER BY %v", d.Dialect.Quote(x)))
	}
	if x := hood.limit; x > 0 {
		query = append(query, "LIMIT ?")
		args = append(args, hood.limit)
	}
	if x := hood.offset; x > 0 {
		query = append(query, "OFFSET ?")
		args = append(args, hood.offset)
	}
	return hood.substituteMarkers(strings.Join(query, " ")), args
}

func (d *Base) Insert(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.InsertSql(model)
	result, err := hood.Exec(sql, args...)
	if err != nil {
		return -1, err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return -1, err
	}
	return Id(id), nil
}

func (d *Base) InsertSql(model *Model) (string, []interface{}) {
	m := 0
	columns, markers, values := columnsMarkersAndValuesForModel(d.Dialect, model, &m)
	quotedColumns := make([]string, 0, len(columns))
	for _, c := range columns {
		quotedColumns = append(quotedColumns, d.Dialect.Quote(c))
	}
	sql := fmt.Sprintf(
		"INSERT INTO %v (%v) VALUES (%v)",
		d.Dialect.Quote(model.Table),
		strings.Join(quotedColumns, ", "),
		strings.Join(markers, ", "),
	)
	return sql, values
}

func (d *Base) Update(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.UpdateSql(model)
	_, err := hood.Exec(sql, args...)
	if err != nil {
		return -1, err
	}
	return model.Pk.Value.(Id), nil
}

func (d *Base) UpdateSql(model *Model) (string, []interface{}) {
	m := 0
	columns, markers, values := columnsMarkersAndValuesForModel(d.Dialect, model, &m)
	pairs := make([]string, 0, len(columns))
	for i, column := range columns {
		pairs = append(pairs, fmt.Sprintf("%v = %v", d.Dialect.Quote(column), markers[i]))
	}
	sql := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v = %v",
		d.Dialect.Quote(model.Table),
		strings.Join(pairs, ", "),
		d.Dialect.Quote(model.Pk.Name),
		d.Dialect.NextMarker(&m),
	)
	values = append(values, model.Pk.Value)
	return sql, values
}

func (d *Base) Delete(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.DeleteSql(model)
	_, err := hood.Exec(sql, args...)
	return args[0].(Id), err
}

func (d *Base) DeleteSql(model *Model) (string, []interface{}) {
	n := 0
	return fmt.Sprintf(
		"DELETE FROM %v WHERE %v = %v",
		d.Dialect.Quote(model.Table),
		d.Dialect.Quote(model.Pk.Name),
		d.Dialect.NextMarker(&n),
	), []interface{}{model.Pk.Value}
}

func (d *Base) CreateTable(hood *Hood, model *Model) error {
	_, err := hood.Exec(d.Dialect.CreateTableSql(model, false))
	return err
}

func (d *Base) CreateTableIfNotExists(hood *Hood, model *Model) error {
	_, err := hood.Exec(d.Dialect.CreateTableSql(model, true))
	return err
}

func (d *Base) CreateTableSql(model *Model, ifNotExists bool) string {
	a := []string{"CREATE TABLE "}
	if ifNotExists {
		a = append(a, "IF NOT EXISTS ")
	}
	a = append(a, d.Dialect.Quote(model.Table), " ( ")
	for i, field := range model.Fields {
		b := []string{
			d.Dialect.Quote(field.Name),
			d.Dialect.SqlType(field.Value, field.Size()),
		}
		if field.NotNull() {
			b = append(b, d.Dialect.KeywordNotNull())
		}
		if x := field.Default(); x != "" {
			b = append(b, d.Dialect.KeywordDefault(x))
		}
		if field.PrimaryKey() {
			b = append(b, d.Dialect.KeywordPrimaryKey())
		}
		if incKeyword := d.Dialect.KeywordAutoIncrement(); field.PrimaryKey() && incKeyword != "" {
			b = append(b, incKeyword)
		}
		a = append(a, strings.Join(b, " "))
		if i < len(model.Fields)-1 {
			a = append(a, ", ")
		}
	}
	a = append(a, " )")
	return strings.Join(a, "")
}

func (d *Base) DropTable(hood *Hood, table string) error {
	_, err := hood.Exec(d.Dialect.DropTableSql(table, false))
	return err
}

func (d *Base) DropTableIfExists(hood *Hood, table string) error {
	_, err := hood.Exec(d.Dialect.DropTableSql(table, true))
	return err
}

func (d *Base) DropTableSql(table string, ifExists bool) string {
	a := []string{"DROP TABLE"}
	if ifExists {
		a = append(a, "IF EXISTS")
	}
	a = append(a, d.Dialect.Quote(table))
	return strings.Join(a, " ")
}

func (d *Base) RenameTable(hood *Hood, from, to string) error {
	_, err := hood.Exec(d.Dialect.RenameTableSql(from, to))
	return err
}

func (d *Base) RenameTableSql(from, to string) string {
	return fmt.Sprintf("ALTER TABLE %v RENAME TO %v", d.Dialect.Quote(from), d.Dialect.Quote(to))
}

func (d *Base) AddColumn(hood *Hood, table, column string, typ interface{}, size int) error {
	_, err := hood.Exec(d.Dialect.AddColumnSql(table, column, typ, size))
	return err
}

func (d *Base) AddColumnSql(table, column string, typ interface{}, size int) string {
	return fmt.Sprintf(
		"ALTER TABLE %v ADD COLUMN %v %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
		d.Dialect.SqlType(typ, size),
	)
}

func (d *Base) RenameColumn(hood *Hood, table, from, to string) error {
	_, err := hood.Exec(d.Dialect.RenameColumnSql(table, from, to))
	return err
}

func (d *Base) RenameColumnSql(table, from, to string) string {
	return fmt.Sprintf(
		"ALTER TABLE %v RENAME COLUMN %v TO %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(from),
		d.Dialect.Quote(to),
	)
}

func (d *Base) ChangeColumn(hood *Hood, table, column string, typ interface{}, size int) error {
	_, err := hood.Exec(d.Dialect.ChangeColumnSql(table, column, typ, size))
	return err
}

func (d *Base) ChangeColumnSql(table, column string, typ interface{}, size int) string {
	return fmt.Sprintf(
		"ALTER TABLE %v ALTER COLUMN %v TYPE %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
		d.Dialect.SqlType(typ, size),
	)
}

func (d *Base) DropColumn(hood *Hood, table, column string) error {
	_, err := hood.Exec(d.Dialect.DropColumnSql(table, column))
	return err
}

func (d *Base) DropColumnSql(table, column string) string {
	return fmt.Sprintf(
		"ALTER TABLE %v DROP COLUMN %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
	)
}

func (d *Base) CreateIndex(hood *Hood, name, table string, unique bool, columns ...string) error {
	_, err := hood.Exec(d.Dialect.CreateIndexSql(name, table, unique, columns...))
	return err
}

func (d *Base) CreateIndexSql(name, table string, unique bool, columns ...string) string {
	a := []string{"CREATE"}
	if unique {
		a = append(a, "UNIQUE")
	}
	quotedColumns := make([]string, 0, len(columns))
	for _, c := range columns {
		quotedColumns = append(quotedColumns, d.Dialect.Quote(c))
	}
	a = append(a, fmt.Sprintf(
		"INDEX %v ON %v (%v)",
		d.Dialect.Quote(name),
		d.Dialect.Quote(table),
		strings.Join(quotedColumns, ", "),
	))
	return strings.Join(a, " ")
}

func (d *Base) DropIndex(hood *Hood, name string) error {
	_, err := hood.Exec(d.Dialect.DropIndexSql(name))
	return err
}

func (d *Base) DropIndexSql(name string) string {
	return fmt.Sprintf("DROP INDEX %v", d.Dialect.Quote(name))
}

func (d *Base) KeywordNotNull() string {
	return "NOT NULL"
}

func (d *Base) KeywordDefault(s string) string {
	return fmt.Sprintf("DEFAULT %v", s)
}

func (d *Base) KeywordPrimaryKey() string {
	return "PRIMARY KEY"
}

func (d *Base) KeywordAutoIncrement() string {
	return "AUTOINCREMENT"
}
<commit_msg>correctly handle Created and Updated time fields (resolves issue #33)<commit_after>package hood

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

type Base struct {
	Dialect Dialect
}

func (d *Base) NextMarker(pos *int) string {
	m := fmt.Sprintf("$%d", *pos+1)
	*pos++
	return m
}

func (d *Base) Quote(s string) string {
	return fmt.Sprintf(`"%s"`, s)
}

func (d *Base) ParseBool(value reflect.Value) bool {
	return value.Bool()
}

func (d *Base) SetModelValue(driverValue, fieldValue reflect.Value) error {
	fieldType := fieldValue.Type()
	switch fieldValue.Type().Kind() {
	case reflect.Bool:
		fieldValue.SetBool(d.Dialect.ParseBool(driverValue.Elem()))
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		fieldValue.SetInt(driverValue.Elem().Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		// reading uint from int value causes panic
		switch driverValue.Elem().Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			fieldValue.SetUint(uint64(driverValue.Elem().Int()))
		default:
			fieldValue.SetUint(driverValue.Elem().Uint())
		}
	case reflect.Float32, reflect.Float64:
		fieldValue.SetFloat(driverValue.Elem().Float())
	case reflect.String:
		fieldValue.SetString(string(driverValue.Elem().Bytes()))
	case reflect.Slice:
		if reflect.TypeOf(driverValue.Interface()).Elem().Kind() == reflect.Uint8 {
			fieldValue.SetBytes(driverValue.Elem().Bytes())
		}
	case reflect.Struct:
		if fieldType == reflect.TypeOf(time.Time{}) {
			fieldValue.Set(driverValue.Elem())
		} else if fieldType == reflect.TypeOf(Updated{}) {
			if time, ok := driverValue.Elem().Interface().(time.Time); ok {
				fieldValue.Set(reflect.ValueOf(Updated{time}))
			} else {
				panic(fmt.Sprintf("cannot set updated value %T", driverValue.Elem().Interface()))
			}
		} else if fieldType == reflect.TypeOf(Created{}) {
			if time, ok := driverValue.Elem().Interface().(time.Time); ok {
				fieldValue.Set(reflect.ValueOf(Created{time}))
			} else {
				panic(fmt.Sprintf("cannot set created value %T", driverValue.Elem().Interface()))
			}
		}
	}
	return nil
}

func (d *Base) ConvertHoodType(f interface{}) interface{} {
	if t, ok := f.(Created); ok {
		return t.Time
	}
	if t, ok := f.(Updated); ok {
		return t.Time
	}
	return f
}

func (d *Base) QuerySql(hood *Hood) (string, []interface{}) {
	query := make([]string, 0, 20)
	args := make([]interface{}, 0, 20)
	if hood.selectTable != "" {
		selector := "*"
		if c := hood.selectCols; len(c) > 0 {
			quotedCols := make([]string, 0, len(hood.selectCols))
			for _, c := range hood.selectCols {
				quotedCols = append(quotedCols, d.Dialect.Quote(c))
			}
			selector = strings.Join(quotedCols, ", ")
		}
		query = append(query, fmt.Sprintf("SELECT %v FROM %v", selector, d.Dialect.Quote(hood.selectTable)))
	}
	for i, op := range hood.joinOps {
		joinType := "INNER"
		switch op {
		case LeftJoin:
			joinType = "LEFT"
		case RightJoin:
			joinType = "RIGHT"
		case FullJoin:
			joinType = "FULL"
		}
		query = append(query, fmt.Sprintf(
			"%s JOIN %v ON %s.%s = %s.%s",
			joinType,
			d.Dialect.Quote(tableName(hood.joinTables[i])),
			d.Dialect.Quote(tableName(hood.selectTable)),
			d.Dialect.Quote(hood.joinCol1[i]),
			d.Dialect.Quote(tableName(hood.joinTables[i])),
			d.Dialect.Quote(hood.joinCol2[i]),
		),
		)
	}
	if x := hood.whereClauses; len(x) > 0 {
		query = append(query, fmt.Sprintf("WHERE %v", strings.Join(x, " AND ")))
		args = append(args, hood.whereArgs...)
	}
	if x := hood.groupBy; x != "" {
		query = append(query, fmt.Sprintf("GROUP BY %v", d.Dialect.Quote(x)))
	}
	if x := hood.havingCond; x != "" {
		query = append(query, fmt.Sprintf("HAVING %v", x))
		args = append(args, hood.havingArgs...)
	}
	if x := hood.orderBy; x != "" {
		query = append(query, fmt.Sprintf("ORDER BY %v", d.Dialect.Quote(x)))
	}
	if x := hood.limit; x > 0 {
		query = append(query, "LIMIT ?")
		args = append(args, hood.limit)
	}
	if x := hood.offset; x > 0 {
		query = append(query, "OFFSET ?")
		args = append(args, hood.offset)
	}
	return hood.substituteMarkers(strings.Join(query, " ")), args
}

func (d *Base) Insert(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.InsertSql(model)
	result, err := hood.Exec(sql, args...)
	if err != nil {
		return -1, err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return -1, err
	}
	return Id(id), nil
}

func (d *Base) InsertSql(model *Model) (string, []interface{}) {
	m := 0
	columns, markers, values := columnsMarkersAndValuesForModel(d.Dialect, model, &m)
	quotedColumns := make([]string, 0, len(columns))
	for _, c := range columns {
		quotedColumns = append(quotedColumns, d.Dialect.Quote(c))
	}
	sql := fmt.Sprintf(
		"INSERT INTO %v (%v) VALUES (%v)",
		d.Dialect.Quote(model.Table),
		strings.Join(quotedColumns, ", "),
		strings.Join(markers, ", "),
	)
	return sql, values
}

func (d *Base) Update(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.UpdateSql(model)
	_, err := hood.Exec(sql, args...)
	if err != nil {
		return -1, err
	}
	return model.Pk.Value.(Id), nil
}

func (d *Base) UpdateSql(model *Model) (string, []interface{}) {
	m := 0
	columns, markers, values := columnsMarkersAndValuesForModel(d.Dialect, model, &m)
	pairs := make([]string, 0, len(columns))
	for i, column := range columns {
		pairs = append(pairs, fmt.Sprintf("%v = %v", d.Dialect.Quote(column), markers[i]))
	}
	sql := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v = %v",
		d.Dialect.Quote(model.Table),
		strings.Join(pairs, ", "),
		d.Dialect.Quote(model.Pk.Name),
		d.Dialect.NextMarker(&m),
	)
	values = append(values, model.Pk.Value)
	return sql, values
}

func (d *Base) Delete(hood *Hood, model *Model) (Id, error) {
	sql, args := d.Dialect.DeleteSql(model)
	_, err := hood.Exec(sql, args...)
	return args[0].(Id), err
}

func (d *Base) DeleteSql(model *Model) (string, []interface{}) {
	n := 0
	return fmt.Sprintf(
		"DELETE FROM %v WHERE %v = %v",
		d.Dialect.Quote(model.Table),
		d.Dialect.Quote(model.Pk.Name),
		d.Dialect.NextMarker(&n),
	), []interface{}{model.Pk.Value}
}

func (d *Base) CreateTable(hood *Hood, model *Model) error {
	_, err := hood.Exec(d.Dialect.CreateTableSql(model, false))
	return err
}

func (d *Base) CreateTableIfNotExists(hood *Hood, model *Model) error {
	_, err := hood.Exec(d.Dialect.CreateTableSql(model, true))
	return err
}

func (d *Base) CreateTableSql(model *Model, ifNotExists bool) string {
	a := []string{"CREATE TABLE "}
	if ifNotExists {
		a = append(a, "IF NOT EXISTS ")
	}
	a = append(a, d.Dialect.Quote(model.Table), " ( ")
	for i, field := range model.Fields {
		b := []string{
			d.Dialect.Quote(field.Name),
			d.Dialect.SqlType(field.Value, field.Size()),
		}
		if field.NotNull() {
			b = append(b, d.Dialect.KeywordNotNull())
		}
		if x := field.Default(); x != "" {
			b = append(b, d.Dialect.KeywordDefault(x))
		}
		if field.PrimaryKey() {
			b = append(b, d.Dialect.KeywordPrimaryKey())
		}
		if incKeyword := d.Dialect.KeywordAutoIncrement(); field.PrimaryKey() && incKeyword != "" {
			b = append(b, incKeyword)
		}
		a = append(a, strings.Join(b, " "))
		if i < len(model.Fields)-1 {
			a = append(a, ", ")
		}
	}
	a = append(a, " )")
	return strings.Join(a, "")
}

func (d *Base) DropTable(hood *Hood, table string) error {
	_, err := hood.Exec(d.Dialect.DropTableSql(table, false))
	return err
}

func (d *Base) DropTableIfExists(hood *Hood, table string) error {
	_, err := hood.Exec(d.Dialect.DropTableSql(table, true))
	return err
}

func (d *Base) DropTableSql(table string, ifExists bool) string {
	a := []string{"DROP TABLE"}
	if ifExists {
		a = append(a, "IF EXISTS")
	}
	a = append(a, d.Dialect.Quote(table))
	return strings.Join(a, " ")
}

func (d *Base) RenameTable(hood *Hood, from, to string) error {
	_, err := hood.Exec(d.Dialect.RenameTableSql(from, to))
	return err
}

func (d *Base) RenameTableSql(from, to string) string {
	return fmt.Sprintf("ALTER TABLE %v RENAME TO %v", d.Dialect.Quote(from), d.Dialect.Quote(to))
}

func (d *Base) AddColumn(hood *Hood, table, column string, typ interface{}, size int) error {
	_, err := hood.Exec(d.Dialect.AddColumnSql(table, column, typ, size))
	return err
}

func (d *Base) AddColumnSql(table, column string, typ interface{}, size int) string {
	return fmt.Sprintf(
		"ALTER TABLE %v ADD COLUMN %v %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
		d.Dialect.SqlType(typ, size),
	)
}

func (d *Base) RenameColumn(hood *Hood, table, from, to string) error {
	_, err := hood.Exec(d.Dialect.RenameColumnSql(table, from, to))
	return err
}

func (d *Base) RenameColumnSql(table, from, to string) string {
	return fmt.Sprintf(
		"ALTER TABLE %v RENAME COLUMN %v TO %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(from),
		d.Dialect.Quote(to),
	)
}

func (d *Base) ChangeColumn(hood *Hood, table, column string, typ interface{}, size int) error {
	_, err := hood.Exec(d.Dialect.ChangeColumnSql(table, column, typ, size))
	return err
}

func (d *Base) ChangeColumnSql(table, column string, typ interface{}, size int) string {
	return fmt.Sprintf(
		"ALTER TABLE %v ALTER COLUMN %v TYPE %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
		d.Dialect.SqlType(typ, size),
	)
}

func (d *Base) DropColumn(hood *Hood, table, column string) error {
	_, err := hood.Exec(d.Dialect.DropColumnSql(table, column))
	return err
}

func (d *Base) DropColumnSql(table, column string) string {
	return fmt.Sprintf(
		"ALTER TABLE %v DROP COLUMN %v",
		d.Dialect.Quote(table),
		d.Dialect.Quote(column),
	)
}

func (d *Base) CreateIndex(hood *Hood, name, table string, unique bool, columns ...string) error {
	_, err := hood.Exec(d.Dialect.CreateIndexSql(name, table, unique, columns...))
	return err
}

func (d *Base) CreateIndexSql(name, table string, unique bool, columns ...string) string {
	a := []string{"CREATE"}
	if unique {
		a = append(a, "UNIQUE")
	}
	quotedColumns := make([]string, 0, len(columns))
	for _, c := range columns {
		quotedColumns = append(quotedColumns, d.Dialect.Quote(c))
	}
	a = append(a, fmt.Sprintf(
		"INDEX %v ON %v (%v)",
		d.Dialect.Quote(name),
		d.Dialect.Quote(table),
		strings.Join(quotedColumns, ", "),
	))
	return strings.Join(a, " ")
}

func (d *Base) DropIndex(hood *Hood, name string) error {
	_, err := hood.Exec(d.Dialect.DropIndexSql(name))
	return err
}

func (d *Base) DropIndexSql(name string) string {
	return fmt.Sprintf("DROP INDEX %v", d.Dialect.Quote(name))
}

func (d *Base) KeywordNotNull() string {
	return "NOT NULL"
}

func (d *Base) KeywordDefault(s string) string {
	return fmt.Sprintf("DEFAULT %v", s)
}

func (d *Base) KeywordPrimaryKey() string {
	return "PRIMARY KEY"
}

func (d *Base) KeywordAutoIncrement() string {
	return "AUTOINCREMENT"
}
<|endoftext|>


<commit_before>package main

import (
    "git.lukas.moe/sn0w/Karen/logger"
    "github.com/bwmarrin/discordgo"
    "time"
)

var BETA_GUILDS = [...]string{
    "180818466847064065", // FADED's Sandbox        (Me)
    "172041631258640384", // P0WERPLANT             (Me)
    "161637499939192832", // Coding Lounge          (Devsome)
    "225168913808228352", // Emily's Space          (Kaaz)
    "267186654312136704", // Shinda Sekai Sensen    (黒ゲロロロ)
    "244110097599430667", // S E K A I              (Senpai /「 ステ 」Abuse)
    "268279577598492672", // ZAKINET                (Senpai /「 ステ 」Abuse)
    "266326434505687041", // Bot Test               (quoththeraven)
    "267658193407049728", // Bot Creation           (quoththeraven)
    "106029722458136576", // Shadow Realm           (WhereIsMyAim)
    "268143270520029187", // Joel's Beasts          (Joel)
    "271346578189582339", // Universe Internet Ltd. (Inside24)
    "270353850085408780", // Turdy Republic         (Moopdedoop)
    "275720670045011968", // Omurice                (Katsurice)
}

// Automatically leaves guilds that are not registered beta testers
func autoLeaver(session *discordgo.Session) {
    for {
        for _, guild := range session.State.Guilds {
            match := false

            for _, betaGuild := range BETA_GUILDS {
                if guild.ID == betaGuild {
                    match = true
                    break
                }
            }

            if !match {
                logger.WARNING.L("beta", "Leaving guild " + guild.ID + " (" + guild.Name + ") because it didn't apply for the beta")
                session.GuildLeave(guild.ID)
            }
        }

        time.Sleep(10 * time.Second)
    }
}
<commit_msg>Whitelist ronin<commit_after>package main

import (
    "git.lukas.moe/sn0w/Karen/logger"
    "github.com/bwmarrin/discordgo"
    "time"
)

var BETA_GUILDS = [...]string{
    "180818466847064065", // FADED's Sandbox        (Me)
    "172041631258640384", // P0WERPLANT             (Me)
    "286474230634381312", // Ronin                  (Me/Serenity)
    "161637499939192832", // Coding Lounge          (Devsome)
    "225168913808228352", // Emily's Space          (Kaaz)
    "267186654312136704", // Shinda Sekai Sensen    (黒ゲロロロ)
    "244110097599430667", // S E K A I              (Senpai /「 ステ 」Abuse)
    "268279577598492672", // ZAKINET                (Senpai /「 ステ 」Abuse)
    "266326434505687041", // Bot Test               (quoththeraven)
    "267658193407049728", // Bot Creation           (quoththeraven)
    "106029722458136576", // Shadow Realm           (WhereIsMyAim)
    "268143270520029187", // Joel's Beasts          (Joel)
    "271346578189582339", // Universe Internet Ltd. (Inside24)
    "270353850085408780", // Turdy Republic         (Moopdedoop)
    "275720670045011968", // Omurice                (Katsurice)
}

// Automatically leaves guilds that are not registered beta testers
func autoLeaver(session *discordgo.Session) {
    for {
        for _, guild := range session.State.Guilds {
            match := false

            for _, betaGuild := range BETA_GUILDS {
                if guild.ID == betaGuild {
                    match = true
                    break
                }
            }

            if !match {
                logger.WARNING.L("beta", "Leaving guild " + guild.ID + " (" + guild.Name + ") because it didn't apply for the beta")
                session.GuildLeave(guild.ID)
            }
        }

        time.Sleep(10 * time.Second)
    }
}
<|endoftext|>


<commit_before>package controller

import (
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite" // sqlite driver
)

func connectDB() *gorm.DB {
	env := os.Getenv("API_RATINGS_ENV")

	if env != "PRODUCTION" {
		db, err := gorm.Open("../../../../admin/database", "database.sqlite")
		if err != nil {
			panic("Failed to connect to database")
		}
		defer db.Close()

		return db
	}

	db, err := gorm.Open("../../../../admin/database", "database.sqlite")
	if err != nil {
		panic("Failed to connect to database")
	}
	defer db.Close()

	return db
}
<commit_msg>Split database connection in read and write connections<commit_after>package controller

import (
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite" // sqlite driver
)

// Load environment
const env string = os.Getenv("API_RATINGS_ENV")

// Load database settings
const readDatabaseURL string = os.Getenv("API_RATINGS_READ_DB_URL")
const readDatabasePort string = os.Getenv("API_RATINGS_READ_DB_PORT")
const writeDatabaseURL string = os.Getenv("API_RATINGS_WRITE_DB_URL")
const writeDatabasePort string = os.Getenv("API_RATINGS_WRITE_DB_PORT")

func connectDB(name string, url string, port string) *gorm.DB {
	db, err := gorm.Open(url, port)
	if err != nil {
		panic("Failed to connect to " + name)
	}
	defer db.Close()

	return db
}

func getReadDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("Read Database", "../"+readDatabaseURL, readDatabasePort)
	}

	return connectDB("Read Database", "../"+readDatabaseURL, readDatabasePort)
}

func getWriteDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("Write Database", "../"+writeDatabaseURL, readDatabasePort)
	}

	return connectDB("Write Database", "../"+writeDatabaseURL, readDatabasePort)
}
<|endoftext|>


<commit_before>package main

import "time"

type LabeledDistributionMaker struct {
	Label             []byte
	DistributionMaker func() Distribution
}

var (
	RedisByteString = []byte("redis") // heap optimization

	RedisUptime = []byte("uptime_in_seconds")

	SixteenGB = float64(16 * 1024 * 1024 * 1024)

	RedisFields = []LabeledDistributionMaker{
		{[]byte("total_connections_received"), func() Distribution { return MWD(ND(5, 1), 0) }},
		{[]byte("expired_keys"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("evicted_keys"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("keyspace_hits"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("keyspace_misses"), func() Distribution { return MWD(ND(50, 1), 0) }},

		{[]byte("instantaneous_ops_per_sec"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("instantaneous_input_kbps"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("instantaneous_output_kbps"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("connected_clients"), func() Distribution { return CWD(ND(50, 1), 0, 10000, 0) }},
		{[]byte("used_memory"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_rss"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_peak"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_lua"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("rdb_changes_since_last_save"), func() Distribution { return CWD(ND(50, 1), 0, 10000, 0) }},

		{[]byte("sync_full"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("sync_partial_ok"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("sync_partial_err"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("pubsub_channels"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("pubsub_patterns"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("latest_fork_usec"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("connected_slaves"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("master_repl_offset"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_active"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_size"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_histlen"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("mem_fragmentation_ratio"), func() Distribution { return CWD(ND(5, 1), 0, 100, 0) }},
		{[]byte("used_cpu_sys"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_user"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_sys_children"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_user_children"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
	}
)

type RedisMeasurement struct {
	timestamp time.Time

	uptime        time.Duration
	distributions []Distribution
}

func NewRedisMeasurement(start time.Time) *RedisMeasurement {
	distributions := make([]Distribution, len(RedisFields))
	for i := range RedisFields {
		distributions[i] = RedisFields[i].DistributionMaker()
	}

	return &RedisMeasurement{
		timestamp:     start,
		uptime:        time.Duration(0),
		distributions: distributions,
	}
}

func (m *RedisMeasurement) Tick(d time.Duration) {
	m.timestamp = m.timestamp.Add(d)
	m.uptime += d

	for i := range m.distributions {
		m.distributions[i].Advance()
	}
}

func (m *RedisMeasurement) ToPoint(p *Point) {
	p.SetMeasurementName(RedisByteString)
	p.SetTimestamp(&m.timestamp)

	p.AppendField(RedisUptime, int64(m.uptime.Seconds()))
	for i := range m.distributions {
		p.AppendField(RedisFields[i].Label, int64(m.distributions[i].Get()))
	}
}
<commit_msg>Redis has its own tags.<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"
)

type LabeledDistributionMaker struct {
	Label             []byte
	DistributionMaker func() Distribution
}

var (
	RedisByteString = []byte("redis") // heap optimization

	RedisUptime = []byte("uptime_in_seconds")

	SixteenGB = float64(16 * 1024 * 1024 * 1024)

	RedisTags = [][]byte{
		[]byte("port"),
		[]byte("server"),
	}

	RedisFields = []LabeledDistributionMaker{
		{[]byte("total_connections_received"), func() Distribution { return MWD(ND(5, 1), 0) }},
		{[]byte("expired_keys"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("evicted_keys"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("keyspace_hits"), func() Distribution { return MWD(ND(50, 1), 0) }},
		{[]byte("keyspace_misses"), func() Distribution { return MWD(ND(50, 1), 0) }},

		{[]byte("instantaneous_ops_per_sec"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("instantaneous_input_kbps"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("instantaneous_output_kbps"), func() Distribution { return WD(ND(1, 1), 0) }},
		{[]byte("connected_clients"), func() Distribution { return CWD(ND(50, 1), 0, 10000, 0) }},
		{[]byte("used_memory"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_rss"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_peak"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("used_memory_lua"), func() Distribution { return CWD(ND(50, 1), 0, SixteenGB, SixteenGB/2) }},
		{[]byte("rdb_changes_since_last_save"), func() Distribution { return CWD(ND(50, 1), 0, 10000, 0) }},

		{[]byte("sync_full"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("sync_partial_ok"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("sync_partial_err"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("pubsub_channels"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("pubsub_patterns"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("latest_fork_usec"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("connected_slaves"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("master_repl_offset"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_active"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_size"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("repl_backlog_histlen"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("mem_fragmentation_ratio"), func() Distribution { return CWD(ND(5, 1), 0, 100, 0) }},
		{[]byte("used_cpu_sys"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_user"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_sys_children"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
		{[]byte("used_cpu_user_children"), func() Distribution { return CWD(ND(5, 1), 0, 1000, 0) }},
	}
)

type RedisMeasurement struct {
	timestamp time.Time

	port, serverName []byte
	uptime           time.Duration
	distributions    []Distribution
}

func NewRedisMeasurement(start time.Time) *RedisMeasurement {
	distributions := make([]Distribution, len(RedisFields))
	for i := range RedisFields {
		distributions[i] = RedisFields[i].DistributionMaker()
	}

	serverName := []byte(fmt.Sprintf("redis_%d", rand.Intn(100000)))
	port := []byte(fmt.Sprintf("%d", rand.Intn(20000)+1024))
	return &RedisMeasurement{
		port:       port,
		serverName: serverName,

		timestamp:     start,
		uptime:        time.Duration(0),
		distributions: distributions,
	}
}

func (m *RedisMeasurement) Tick(d time.Duration) {
	m.timestamp = m.timestamp.Add(d)
	m.uptime += d

	for i := range m.distributions {
		m.distributions[i].Advance()
	}
}

func (m *RedisMeasurement) ToPoint(p *Point) {
	p.SetMeasurementName(RedisByteString)
	p.SetTimestamp(&m.timestamp)

	p.AppendTag(RedisTags[0], m.port)
	p.AppendTag(RedisTags[1], m.serverName)

	p.AppendField(RedisUptime, int64(m.uptime.Seconds()))
	for i := range m.distributions {
		p.AppendField(RedisFields[i].Label, int64(m.distributions[i].Get()))
	}
}
<|endoftext|>


<commit_before>// +build android

package ipc

import (
	"fmt"
	"runtime"

	jutil "veyron.io/jni/util"
	jsecurity "veyron.io/jni/veyron2/security"
	"veyron.io/veyron/veyron2/security"
)

// #cgo LDFLAGS: -ljniwrapper
// #include "jni_wrapper.h"
import "C"

func goDispatcher(env *C.JNIEnv, jDispatcher C.jobject) (*dispatcher, error) {
	// We cannot cache Java environments as they are only valid in the current
	// thread.  We can, however, cache the Java VM and obtain an environment
	// from it in whatever thread happens to be running at the time.
	var jVM *C.JavaVM
	if status := C.GetJavaVM(env, &jVM); status != 0 {
		return nil, fmt.Errorf("couldn't get Java VM from the (Java) environment")
	}
	// Reference Java dispatcher; it will be de-referenced when the go
	// dispatcher created below is garbage-collected (through the finalizer
	// callback we setup below).
	jDispatcher = C.NewGlobalRef(env, jDispatcher)
	d := &dispatcher{
		jVM:         jVM,
		jDispatcher: jDispatcher,
	}
	runtime.SetFinalizer(d, func(d *dispatcher) {
		jEnv, freeFunc := jutil.GetEnv(d.jVM)
		env := (*C.JNIEnv)(jEnv)
		defer freeFunc()
		C.DeleteGlobalRef(env, d.jDispatcher)
	})

	return d, nil
}

type dispatcher struct {
	jVM         *C.JavaVM
	jDispatcher C.jobject
}

func (d *dispatcher) Lookup(suffix, method string) (interface{}, security.Authorizer, error) {
	// Get Java environment.
	env, freeFunc := jutil.GetEnv(d.jVM)
	defer freeFunc()

	// Call Java dispatcher's lookup() method.
	serviceObjectWithAuthorizerSign := jutil.ClassSign("io.veyron.veyron.veyron2.ipc.ServiceObjectWithAuthorizer")
	tempJObj, err := jutil.CallObjectMethod(env, d.jDispatcher, "lookup", []jutil.Sign{jutil.StringSign}, serviceObjectWithAuthorizerSign, suffix)
	jObj := C.jobject(tempJObj)
	if err != nil {
		return nil, nil, fmt.Errorf("error invoking Java dispatcher's lookup() method: %v", err)
	}
	if jObj == nil {
		// Lookup returned null, which means that the dispatcher isn't handling the object -
		// this is not an error.
		return nil, nil, nil
	}

	// Extract the Java service object and Authorizer.
	jServiceObj, err := jutil.CallObjectMethod(env, jObj, "getServiceObject", nil, jutil.ObjectSign)
	if err != nil {
		return nil, nil, err
	}
	if jServiceObj == nil {
		return nil, nil, fmt.Errorf("null service object returned by Java's ServiceObjectWithAuthorizer")
	}
	authSign := jutil.ClassSign("io.veyron.veyron.veyron2.security.Authorizer")
	jAuth, err := jutil.CallObjectMethod(env, jObj, "getAuthorizer", nil, authSign)
	if err != nil {
		return nil, nil, err
	}

	// Create Go Invoker and Authorizer.
	i, err := goInvoker((*C.JNIEnv)(env), C.jobject(jServiceObj))
	if err != nil {
		return nil, nil, err
	}
	a, err := jsecurity.GoAuthorizer(env, jAuth)
	if err != nil {
		return nil, nil, err
	}
	return i, a, nil
}
<commit_msg>veyron.io/jni: Fix dispatcher implementation interface.<commit_after>// +build android

package ipc

import (
	"fmt"
	"runtime"

	jutil "veyron.io/jni/util"
	jsecurity "veyron.io/jni/veyron2/security"
	"veyron.io/veyron/veyron2/security"
)

// #cgo LDFLAGS: -ljniwrapper
// #include "jni_wrapper.h"
import "C"

func goDispatcher(env *C.JNIEnv, jDispatcher C.jobject) (*dispatcher, error) {
	// We cannot cache Java environments as they are only valid in the current
	// thread.  We can, however, cache the Java VM and obtain an environment
	// from it in whatever thread happens to be running at the time.
	var jVM *C.JavaVM
	if status := C.GetJavaVM(env, &jVM); status != 0 {
		return nil, fmt.Errorf("couldn't get Java VM from the (Java) environment")
	}
	// Reference Java dispatcher; it will be de-referenced when the go
	// dispatcher created below is garbage-collected (through the finalizer
	// callback we setup below).
	jDispatcher = C.NewGlobalRef(env, jDispatcher)
	d := &dispatcher{
		jVM:         jVM,
		jDispatcher: jDispatcher,
	}
	runtime.SetFinalizer(d, func(d *dispatcher) {
		jEnv, freeFunc := jutil.GetEnv(d.jVM)
		env := (*C.JNIEnv)(jEnv)
		defer freeFunc()
		C.DeleteGlobalRef(env, d.jDispatcher)
	})

	return d, nil
}

type dispatcher struct {
	jVM         *C.JavaVM
	jDispatcher C.jobject
}

func (d *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
	// Get Java environment.
	env, freeFunc := jutil.GetEnv(d.jVM)
	defer freeFunc()

	// Call Java dispatcher's lookup() method.
	serviceObjectWithAuthorizerSign := jutil.ClassSign("io.veyron.veyron.veyron2.ipc.ServiceObjectWithAuthorizer")
	tempJObj, err := jutil.CallObjectMethod(env, d.jDispatcher, "lookup", []jutil.Sign{jutil.StringSign}, serviceObjectWithAuthorizerSign, suffix)
	jObj := C.jobject(tempJObj)
	if err != nil {
		return nil, nil, fmt.Errorf("error invoking Java dispatcher's lookup() method: %v", err)
	}
	if jObj == nil {
		// Lookup returned null, which means that the dispatcher isn't handling the object -
		// this is not an error.
		return nil, nil, nil
	}

	// Extract the Java service object and Authorizer.
	jServiceObj, err := jutil.CallObjectMethod(env, jObj, "getServiceObject", nil, jutil.ObjectSign)
	if err != nil {
		return nil, nil, err
	}
	if jServiceObj == nil {
		return nil, nil, fmt.Errorf("null service object returned by Java's ServiceObjectWithAuthorizer")
	}
	authSign := jutil.ClassSign("io.veyron.veyron.veyron2.security.Authorizer")
	jAuth, err := jutil.CallObjectMethod(env, jObj, "getAuthorizer", nil, authSign)
	if err != nil {
		return nil, nil, err
	}

	// Create Go Invoker and Authorizer.
	i, err := goInvoker((*C.JNIEnv)(env), C.jobject(jServiceObj))
	if err != nil {
		return nil, nil, err
	}
	a, err := jsecurity.GoAuthorizer(env, jAuth)
	if err != nil {
		return nil, nil, err
	}
	return i, a, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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 windows

import (
	"context"
	"regexp"
	"strings"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	"github.com/onsi/ginkgo"
)

var _ = SIGDescribe("DNS", func() {

	ginkgo.BeforeEach(func() {
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
	})

	f := framework.NewDefaultFramework("dns")

	ginkgo.It("should support configurable pod DNS servers", func() {
		ginkgo.By("Preparing a test DNS service with injected DNS names...")
		testInjectedIP := "1.1.1.1"
		testSearchPath := "resolv.conf.local"

		ginkgo.By("Creating a pod with dnsPolicy=None and customized dnsConfig...")
		testUtilsPod := e2epod.NewAgnhostPod(f.Namespace.Name, "e2e-dns-utils", nil, nil, nil)
		testUtilsPod.Spec.DNSPolicy = v1.DNSNone
		testUtilsPod.Spec.DNSConfig = &v1.PodDNSConfig{
			Nameservers: []string{testInjectedIP},
			Searches:    []string{testSearchPath},
		}
		testUtilsPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(), testUtilsPod, metav1.CreateOptions{})
		framework.ExpectNoError(err)
		framework.Logf("Created pod %v", testUtilsPod)
		defer func() {
			framework.Logf("Deleting pod %s...", testUtilsPod.Name)
			if err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(context.TODO(), testUtilsPod.Name, *metav1.NewDeleteOptions(0)); err != nil {
				framework.Failf("Failed to delete pod %s: %v", testUtilsPod.Name, err)
			}
		}()
		framework.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(f.ClientSet, testUtilsPod.Name, f.Namespace.Name), "failed to wait for pod %s to be running", testUtilsPod.Name)

		ginkgo.By("Verifying customized DNS option is configured on pod...")
		cmd := []string{"ipconfig", "/all"}
		stdout, _, err := f.ExecWithOptions(framework.ExecOptions{
			Command:       cmd,
			Namespace:     f.Namespace.Name,
			PodName:       testUtilsPod.Name,
			ContainerName: "agnhost-container",
			CaptureStdout: true,
			CaptureStderr: true,
		})
		framework.ExpectNoError(err)

		framework.Logf("ipconfig /all:\n%s", stdout)
		dnsRegex, err := regexp.Compile(`DNS Servers[\s*.]*:(\s*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})+`)
		framework.ExpectNoError(err)

		if dnsRegex.MatchString(stdout) {
			match := dnsRegex.FindString(stdout)

			if !strings.Contains(match, testInjectedIP) {
				framework.Failf("customized DNS options not found in ipconfig /all, got: %s", match)
			}
		} else {
			framework.Failf("cannot find DNS server info in ipconfig /all output: \n%s", stdout)
		}
		// TODO: Add more test cases for other DNSPolicies.
	})
})
<commit_msg>adding windows os selector to the dnsPolicy tests adding a feature selector to the windows Describe dns test<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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 windows

import (
	"context"
	"regexp"
	"strings"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	"github.com/onsi/ginkgo"
)

var _ = SIGDescribe("[Feature:Windows] DNS", func() {

	ginkgo.BeforeEach(func() {
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
	})

	f := framework.NewDefaultFramework("dns")

	ginkgo.It("should support configurable pod DNS servers", func() {
		ginkgo.By("Preparing a test DNS service with injected DNS names...")
		testInjectedIP := "1.1.1.1"
		testSearchPath := "resolv.conf.local"

		ginkgo.By("Creating a pod with dnsPolicy=None and customized dnsConfig...")
		testUtilsPod := e2epod.NewAgnhostPod(f.Namespace.Name, "e2e-dns-utils", nil, nil, nil)
		testUtilsPod.Spec.DNSPolicy = v1.DNSNone
		testUtilsPod.Spec.DNSConfig = &v1.PodDNSConfig{
			Nameservers: []string{testInjectedIP},
			Searches:    []string{testSearchPath},
		}
		testUtilsPod.Spec.NodeSelector = map[string]string{
			"kubernetes.io/os": "windows",
		}
		testUtilsPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(), testUtilsPod, metav1.CreateOptions{})
		framework.ExpectNoError(err)
		framework.Logf("Created pod %v", testUtilsPod)
		defer func() {
			framework.Logf("Deleting pod %s...", testUtilsPod.Name)
			if err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(context.TODO(), testUtilsPod.Name, *metav1.NewDeleteOptions(0)); err != nil {
				framework.Failf("Failed to delete pod %s: %v", testUtilsPod.Name, err)
			}
		}()
		framework.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(f.ClientSet, testUtilsPod.Name, f.Namespace.Name), "failed to wait for pod %s to be running", testUtilsPod.Name)

		ginkgo.By("Verifying customized DNS option is configured on pod...")
		cmd := []string{"ipconfig", "/all"}
		stdout, _, err := f.ExecWithOptions(framework.ExecOptions{
			Command:       cmd,
			Namespace:     f.Namespace.Name,
			PodName:       testUtilsPod.Name,
			ContainerName: "agnhost-container",
			CaptureStdout: true,
			CaptureStderr: true,
		})
		framework.ExpectNoError(err)

		framework.Logf("ipconfig /all:\n%s", stdout)
		dnsRegex, err := regexp.Compile(`DNS Servers[\s*.]*:(\s*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})+`)
		framework.ExpectNoError(err)

		if dnsRegex.MatchString(stdout) {
			match := dnsRegex.FindString(stdout)

			if !strings.Contains(match, testInjectedIP) {
				framework.Failf("customized DNS options not found in ipconfig /all, got: %s", match)
			}
		} else {
			framework.Failf("cannot find DNS server info in ipconfig /all output: \n%s", stdout)
		}
		// TODO: Add more test cases for other DNSPolicies.
	})
})
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/miekg/dns"
	"os"
	"strings"
	"time"
)

const (
	TIMEOUT time.Duration = 5 // seconds
)

var (
	localm *dns.Msg
	localc *dns.Client
	conf   *dns.ClientConfig
)

func localQuery(qname string, qtype uint16) (r *dns.Msg, err error) {
	localm.SetQuestion(qname, qtype)
	for i := range conf.Servers {
		server := conf.Servers[i]
		r, err := localc.Exchange(localm, server+":"+conf.Port)
		if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
			return r, err
		}
	}
	return nil, errors.New("No name server to answer the question")
}

func main() {
	var err error
	if len(os.Args) != 2 {
		fmt.Printf("%s ZONE\n", os.Args[0])
		os.Exit(1)
	}
	conf, err = dns.ClientConfigFromFile("/etc/resolv.conf")
	if conf == nil {
		fmt.Printf("Cannot initialize the local resolver: %s\n", err)
		os.Exit(1)
	}
	localm = new(dns.Msg)
	localm.MsgHdr.RecursionDesired = true
	localm.Question = make([]dns.Question, 1)
	localc = new(dns.Client)
	localc.ReadTimeout = TIMEOUT * 1e9
	r, err := localQuery(dns.Fqdn(os.Args[1]), dns.TypeNS)
	if r == nil {
		fmt.Printf("Cannot retrieve the list of name servers for %s: %s\n", dns.Fqdn(os.Args[1]), err)
		os.Exit(1)
	}
	if r.Rcode == dns.RcodeNameError {
		fmt.Printf("No such domain %s\n", dns.Fqdn(os.Args[1]))
		os.Exit(1)
	}
	m := new(dns.Msg)
	m.MsgHdr.RecursionDesired = false
	m.Question = make([]dns.Question, 1)
	c := new(dns.Client)
	c.ReadTimeout = TIMEOUT * 1e9
	success := true
	numNS := 0
	for _, ans := range r.Answer {
		switch ans.(type) {
		case *dns.RR_NS:
			nameserver := ans.(*dns.RR_NS).Ns
			numNS += 1
			ips := make([]string, 0)
			fmt.Printf("%s : ", nameserver)
			ra, err := localQuery(nameserver, dns.TypeA)
			if ra == nil {
				fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, err)
				os.Exit(1)
			}
			if ra.Rcode != dns.RcodeSuccess {
				fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, dns.Rcode_str[ra.Rcode])
				os.Exit(1)
			}
			for _, ansa := range ra.Answer {
				switch ansa.(type) {
				case *dns.RR_A:
					ips = append(ips, ansa.(*dns.RR_A).A.String())
				}
			}
			raaaa, err := localQuery(nameserver, dns.TypeAAAA)
			if raaaa == nil {
				fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, err)
				os.Exit(1)
			}
			if raaaa.Rcode != dns.RcodeSuccess {
				fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, dns.Rcode_str[raaaa.Rcode])
				os.Exit(1)
			}
			for _, ansaaaa := range raaaa.Answer {
				switch ansaaaa.(type) {
				case *dns.RR_AAAA:
					ips = append(ips, ansaaaa.(*dns.RR_AAAA).AAAA.String())
				}
			}
			if len(ips) == 0 {
				success = false
				fmt.Printf("No IP address for this server")
			}
			for _, ip := range ips {
				m.Question[0] = dns.Question{dns.Fqdn(os.Args[1]), dns.TypeSOA, dns.ClassINET}
				nsAddressPort := ""
				if strings.ContainsAny(":", ip) {
					// IPv6 address
					nsAddressPort = "[" + ip + "]:53"
				} else {
					nsAddressPort = ip + ":53"
				}
				soa, err := c.Exchange(m, nsAddressPort)
				// TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end
				if soa == nil {
					success = false
					fmt.Printf("%s (%s) ", ip, err)
				} else {
					if soa.Rcode != dns.RcodeSuccess {
						success = false
						fmt.Printf("%s (%s) ", ips, dns.Rcode_str[soa.Rcode])
					} else {
						if len(soa.Answer) == 0 { // May happen if the server is a recursor, not authoritative, since we query with RD=0
							success = false
							fmt.Printf("%s (0 answer) ", ip)
						} else {
							rsoa := soa.Answer[0]
							switch rsoa.(type) {
							case *dns.RR_SOA:
								if soa.MsgHdr.Authoritative {
									// TODO: test if all name servers have the same serial ?
									fmt.Printf("%s (%d) ", ips, rsoa.(*dns.RR_SOA).Serial)
								} else {
									success = false
									fmt.Printf("%s (not authoritative) ", ips)
								}
							}
						}
					}
				}
			}
			fmt.Printf("\n")
		}
	}
	if numNS == 0 {
		fmt.Printf("No NS records for \"%s\". It is probably a CNAME to a domain but not a zone\n", dns.Fqdn(os.Args[1]))
		os.Exit(1)
	}
	if success {
		os.Exit(0)
	}
	os.Exit(1)
}
<commit_msg>Dont nest so deep. Used a goto for now<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/miekg/dns"
	"os"
	"strings"
	"time"
)

const (
	TIMEOUT time.Duration = 5 // seconds
)

var (
	localm *dns.Msg
	localc *dns.Client
	conf   *dns.ClientConfig
)

func localQuery(qname string, qtype uint16) (*dns.Msg, error) {
	localm.SetQuestion(qname, qtype)
	for i := range conf.Servers {
		server := conf.Servers[i]
		r, err := localc.Exchange(localm, server+":"+conf.Port)
		if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
			return r, err
		}
	}
	return nil, errors.New("No name server to answer the question")
}

func main() {
	var err error
	if len(os.Args) != 2 {
		fmt.Printf("%s ZONE\n", os.Args[0])
		os.Exit(1)
	}
	conf, err = dns.ClientConfigFromFile("/etc/resolv.conf")
	if conf == nil {
		fmt.Printf("Cannot initialize the local resolver: %s\n", err)
		os.Exit(1)
	}
	localm = new(dns.Msg)
	localm.MsgHdr.RecursionDesired = true
	localm.Question = make([]dns.Question, 1)
	localc = new(dns.Client)
	localc.ReadTimeout = TIMEOUT * 1e9
	r, err := localQuery(dns.Fqdn(os.Args[1]), dns.TypeNS)
	if r == nil {
		fmt.Printf("Cannot retrieve the list of name servers for %s: %s\n", dns.Fqdn(os.Args[1]), err)
		os.Exit(1)
	}
	if r.Rcode == dns.RcodeNameError {
		fmt.Printf("No such domain %s\n", dns.Fqdn(os.Args[1]))
		os.Exit(1)
	}
	m := new(dns.Msg)
	m.MsgHdr.RecursionDesired = false
	m.Question = make([]dns.Question, 1)
	c := new(dns.Client)
	c.ReadTimeout = TIMEOUT * 1e9
	success := true
	numNS := 0
	for _, ans := range r.Answer {
		switch ans.(type) {
		case *dns.RR_NS:
			nameserver := ans.(*dns.RR_NS).Ns
			numNS += 1
			ips := make([]string, 0)
			fmt.Printf("%s : ", nameserver)
			ra, err := localQuery(nameserver, dns.TypeA)
			if ra == nil {
				fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, err)
				os.Exit(1)
			}
			if ra.Rcode != dns.RcodeSuccess {
				fmt.Printf("Error getting the IPv4 address of %s: %s\n", nameserver, dns.Rcode_str[ra.Rcode])
				os.Exit(1)
			}
			for _, ansa := range ra.Answer {
				switch ansa.(type) {
				case *dns.RR_A:
					ips = append(ips, ansa.(*dns.RR_A).A.String())
				}
			}
			raaaa, err := localQuery(nameserver, dns.TypeAAAA)
			if raaaa == nil {
				fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, err)
				os.Exit(1)
			}
			if raaaa.Rcode != dns.RcodeSuccess {
				fmt.Printf("Error getting the IPv6 address of %s: %s\n", nameserver, dns.Rcode_str[raaaa.Rcode])
				os.Exit(1)
			}
			for _, ansaaaa := range raaaa.Answer {
				switch ansaaaa.(type) {
				case *dns.RR_AAAA:
					ips = append(ips, ansaaaa.(*dns.RR_AAAA).AAAA.String())
				}
			}
			if len(ips) == 0 {
				success = false
				fmt.Printf("No IP address for this server")
			}
			for _, ip := range ips {
				m.Question[0] = dns.Question{dns.Fqdn(os.Args[1]), dns.TypeSOA, dns.ClassINET}
				nsAddressPort := ""
				if strings.ContainsAny(":", ip) {
					// IPv6 address
					nsAddressPort = "[" + ip + "]:53"
				} else {
					nsAddressPort = ip + ":53"
				}
				soa, err := c.Exchange(m, nsAddressPort)
				// TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end
				if soa == nil {
					success = false
					fmt.Printf("%s (%s) ", ip, err)
					goto Next
				}
				if soa.Rcode != dns.RcodeSuccess {
					success = false
					fmt.Printf("%s (%s) ", ips, dns.Rcode_str[soa.Rcode])
					goto Next
				}
				if len(soa.Answer) == 0 { // May happen if the server is a recursor, not authoritative, since we query with RD=0
					success = false
					fmt.Printf("%s (0 answer) ", ip)
					goto Next
				}
				rsoa := soa.Answer[0]
				switch rsoa.(type) {
				case *dns.RR_SOA:
					if soa.MsgHdr.Authoritative {
						// TODO: test if all name servers have the same serial ?
						fmt.Printf("%s (%d) ", ips, rsoa.(*dns.RR_SOA).Serial)
					} else {
						success = false
						fmt.Printf("%s (not authoritative) ", ips)
					}
				}
			}
		Next:
			fmt.Printf("\n")
		}
	}
	if numNS == 0 {
		fmt.Printf("No NS records for \"%s\". It is probably a CNAME to a domain but not a zone\n", dns.Fqdn(os.Args[1]))
		os.Exit(1)
	}
	if success {
		os.Exit(0)
	}
	os.Exit(1)
}
<|endoftext|>