<commit_before>// Copyright 2011 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 proxy

import (
	"net"
	"strings"
)

// A PerHost directs connections to a default Dailer unless the hostname
// requested matches one of a number of exceptions.
type PerHost struct {
	def, bypass Dialer

	bypassNetworks []*net.IPNet
	bypassIPs      []net.IP
	bypassZones    []string
	bypassHosts    []string
}

// NewPerHost returns a PerHost Dialer that directs connections to either
// defaultDialer or bypass, depending on whether the connection matches one of
// the configured rules.
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
	return &PerHost{
		def:    defaultDialer,
		bypass: bypass,
	}
}

// Dial connects to the address addr on the network net through either
// defaultDialer or bypass.
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}

	return p.dialerForRequest(host).Dial(network, addr)
}

func (p *PerHost) dialerForRequest(host string) Dialer {
	if ip := net.ParseIP(host); ip != nil {
		for _, net := range p.bypassNetworks {
			if net.Contains(ip) {
				return p.bypass
			}
		}
		for _, bypassIP := range p.bypassIPs {
			if bypassIP.Equal(ip) {
				return p.bypass
			}
		}
		return p.def
	}

	for _, zone := range p.bypassZones {
		if strings.HasSuffix(host, zone) {
			return p.bypass
		}
		if host == zone[1:] {
			// For a zone "example.com", we match "example.com"
			// too.
			return p.bypass
		}
	}
	for _, bypassHost := range p.bypassHosts {
		if bypassHost == host {
			return p.bypass
		}
	}
	return p.def
}

// AddFromString parses a string that contains comma-separated values
// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a hostname
// (localhost). A best effort is made to parse the string and errors are
// ignored.
func (p *PerHost) AddFromString(s string) {
	hosts := strings.Split(s, ",")
	for _, host := range hosts {
		host = strings.TrimSpace(host)
		if len(host) == 0 {
			continue
		}
		if strings.Contains(host, "/") {
			// We assume that it's a CIDR address like 127.0.0.0/8
			if _, net, err := net.ParseCIDR(host); err == nil {
				p.AddNetwork(net)
			}
			continue
		}
		if ip := net.ParseIP(host); ip != nil {
			p.AddIP(ip)
			continue
		}
		if strings.HasPrefix(host, "*.") {
			p.AddZone(host[1:])
			continue
		}
		p.AddHost(host)
	}
}

// AddIP specifies an IP address that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match an IP.
func (p *PerHost) AddIP(ip net.IP) {
	p.bypassIPs = append(p.bypassIPs, ip)
}

// AddIP specifies an IP range that will use the bypass proxy. Note that this
// will only take effect if a literal IP address is dialed. A connection to a
// named host will never match.
func (p *PerHost) AddNetwork(net *net.IPNet) {
	p.bypassNetworks = append(p.bypassNetworks, net)
}

// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
// "example.com" matches "example.com" and all of its subdomains.
func (p *PerHost) AddZone(zone string) {
	if strings.HasSuffix(zone, ".") {
		zone = zone[:len(zone)-1]
	}
	if !strings.HasPrefix(zone, ".") {
		zone = "." + zone
	}
	p.bypassZones = append(p.bypassZones, zone)
}

// AddHost specifies a hostname that will use the bypass proxy.
func (p *PerHost) AddHost(host string) {
	if strings.HasSuffix(host, ".") {
		host = host[:len(host)-1]
	}
	p.bypassHosts = append(p.bypassHosts, host)
}
<commit_msg>proxy: fix wrong function name in comment<commit_after>// Copyright 2011 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 proxy

import (
	"net"
	"strings"
)

// A PerHost directs connections to a default Dailer unless the hostname
// requested matches one of a number of exceptions.
type PerHost struct {
	def, bypass Dialer

	bypassNetworks []*net.IPNet
	bypassIPs      []net.IP
	bypassZones    []string
	bypassHosts    []string
}

// NewPerHost returns a PerHost Dialer that directs connections to either
// defaultDialer or bypass, depending on whether the connection matches one of
// the configured rules.
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
	return &PerHost{
		def:    defaultDialer,
		bypass: bypass,
	}
}

// Dial connects to the address addr on the given network through either
// defaultDialer or bypass.
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}

	return p.dialerForRequest(host).Dial(network, addr)
}

func (p *PerHost) dialerForRequest(host string) Dialer {
	if ip := net.ParseIP(host); ip != nil {
		for _, net := range p.bypassNetworks {
			if net.Contains(ip) {
				return p.bypass
			}
		}
		for _, bypassIP := range p.bypassIPs {
			if bypassIP.Equal(ip) {
				return p.bypass
			}
		}
		return p.def
	}

	for _, zone := range p.bypassZones {
		if strings.HasSuffix(host, zone) {
			return p.bypass
		}
		if host == zone[1:] {
			// For a zone "example.com", we match "example.com"
			// too.
			return p.bypass
		}
	}
	for _, bypassHost := range p.bypassHosts {
		if bypassHost == host {
			return p.bypass
		}
	}
	return p.def
}

// AddFromString parses a string that contains comma-separated values
// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a hostname
// (localhost). A best effort is made to parse the string and errors are
// ignored.
func (p *PerHost) AddFromString(s string) {
	hosts := strings.Split(s, ",")
	for _, host := range hosts {
		host = strings.TrimSpace(host)
		if len(host) == 0 {
			continue
		}
		if strings.Contains(host, "/") {
			// We assume that it's a CIDR address like 127.0.0.0/8
			if _, net, err := net.ParseCIDR(host); err == nil {
				p.AddNetwork(net)
			}
			continue
		}
		if ip := net.ParseIP(host); ip != nil {
			p.AddIP(ip)
			continue
		}
		if strings.HasPrefix(host, "*.") {
			p.AddZone(host[1:])
			continue
		}
		p.AddHost(host)
	}
}

// AddIP specifies an IP address that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match an IP.
func (p *PerHost) AddIP(ip net.IP) {
	p.bypassIPs = append(p.bypassIPs, ip)
}

// AddNetwork specifies an IP range that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match.
func (p *PerHost) AddNetwork(net *net.IPNet) {
	p.bypassNetworks = append(p.bypassNetworks, net)
}

// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
// "example.com" matches "example.com" and all of its subdomains.
func (p *PerHost) AddZone(zone string) {
	if strings.HasSuffix(zone, ".") {
		zone = zone[:len(zone)-1]
	}
	if !strings.HasPrefix(zone, ".") {
		zone = "." + zone
	}
	p.bypassZones = append(p.bypassZones, zone)
}

// AddHost specifies a hostname that will use the bypass proxy.
func (p *PerHost) AddHost(host string) {
	if strings.HasSuffix(host, ".") {
		host = host[:len(host)-1]
	}
	p.bypassHosts = append(p.bypassHosts, host)
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 store

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/gogo/protobuf/proto"

	cfg "istio.io/istio/mixer/pkg/config/proto"
)

func TestQueue(t *testing.T) {
	count := 10
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	donec := make(chan struct{})
	evs := []Event{}
	go func() {
		for ev := range q.chout {
			evs = append(evs, ev)
			if len(evs) >= count {
				break
			}
		}
		close(donec)
	}()
	for i := 0; i < count; i++ {
		chin <- BackendEvent{
			Type: Update,
			Key:  Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{
				Spec: map[string]interface{}{
					"name": "h1",
				},
			},
		}
	}
	<-donec
	if len(evs) != count {
		t.Errorf("Got %d Want %d", len(evs), count)
	}
	for i, ev := range evs {
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("%d: Got name %s Want %d", i, ev.Name, i)
		}
	}
}

func TestQueueFail(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	chin <- BackendEvent{
		Type:  Update,
		Key:   Key{Kind: "Unknown", Namespace: "ns", Name: "unknown"},
		Value: &BackEndResource{Spec: map[string]interface{}{"foo": "bar"}},
	}
	select {
	case ev := <-q.chout:
		t.Errorf("Got %+v, Want nothing", ev)
	default:
		// pass
	}
	chin <- BackendEvent{
		Type:  Update,
		Key:   Key{Kind: "Handler", Namespace: "ns", Name: "illformed"},
		Value: &BackEndResource{Spec: map[string]interface{}{"foo": "bar"}},
	}
	select {
	case ev := <-q.chout:
		t.Errorf("Got %+v, Want nothing", ev)
	default:
		// pass
	}
}

func TestQueueSync(t *testing.T) {
	count := 10
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	for i := 0; i < count; i++ {
		chin <- BackendEvent{
			Type:  Update,
			Key:   Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{},
		}
	}
	for i := 0; i < count; i++ {
		ev := <-q.chout
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("Got name %s Want %d", ev.Name, i)
		}
	}
}

func TestQueueCancelClosesOutputChannel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	donec := make(chan struct{})
	go func() {
		for range q.chout {
		}
		close(donec)
	}()
	cancel()
	<-donec
}

func TestQueueCancelSync(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	for i := 0; i < choutBufSize+5; i++ {
		chin <- BackendEvent{
			Type:  Update,
			Key:   Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{},
		}
	}
	cancel()
	// Wait for the queue's run loop to end.
	time.Sleep(time.Millisecond)
	// Read the bufferred events.
	for i := 0; i < choutBufSize; i++ {
		ev := <-q.chout
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("Got name %s Want %d", ev.Name, i)
		}
	}
	// After the buffer runs out, it should return an empty since it's closed due to cancel.
	ev := <-q.chout
	if ev.Name != "" {
		t.Errorf("Got %+v, Want empty", ev)
	}
}
<commit_msg>fix queue_test flakiness (#1320)<commit_after>// Copyright 2017 Istio 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 store

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/gogo/protobuf/proto"

	cfg "istio.io/istio/mixer/pkg/config/proto"
)

func TestQueue(t *testing.T) {
	count := 10
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	donec := make(chan struct{})
	evs := []Event{}
	go func() {
		for ev := range q.chout {
			evs = append(evs, ev)
			if len(evs) >= count {
				break
			}
		}
		close(donec)
	}()
	for i := 0; i < count; i++ {
		chin <- BackendEvent{
			Type: Update,
			Key:  Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{
				Spec: map[string]interface{}{
					"name": "h1",
				},
			},
		}
	}
	<-donec
	if len(evs) != count {
		t.Errorf("Got %d Want %d", len(evs), count)
	}
	for i, ev := range evs {
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("%d: Got name %s Want %d", i, ev.Name, i)
		}
	}
}

func TestQueueFail(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	chin <- BackendEvent{
		Type:  Update,
		Key:   Key{Kind: "Unknown", Namespace: "ns", Name: "unknown"},
		Value: &BackEndResource{Spec: map[string]interface{}{"foo": "bar"}},
	}
	select {
	case ev := <-q.chout:
		t.Errorf("Got %+v, Want nothing", ev)
	default:
		// pass
	}
	chin <- BackendEvent{
		Type:  Update,
		Key:   Key{Kind: "Handler", Namespace: "ns", Name: "illformed"},
		Value: &BackEndResource{Spec: map[string]interface{}{"foo": "bar"}},
	}
	select {
	case ev := <-q.chout:
		t.Errorf("Got %+v, Want nothing", ev)
	default:
		// pass
	}
}

func TestQueueSync(t *testing.T) {
	count := 10
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	defer cancel()
	for i := 0; i < count; i++ {
		chin <- BackendEvent{
			Type:  Update,
			Key:   Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{},
		}
	}
	for i := 0; i < count; i++ {
		ev := <-q.chout
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("Got name %s Want %d", ev.Name, i)
		}
	}
}

func TestQueueCancelClosesOutputChannel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	donec := make(chan struct{})
	go func() {
		for range q.chout {
		}
		close(donec)
	}()
	cancel()
	<-donec
}

func TestQueueCancelSync(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	chin := make(chan BackendEvent)
	q := newQueue(ctx, chin, map[string]proto.Message{"Handler": &cfg.Handler{}})
	for i := 0; i < choutBufSize+5; i++ {
		chin <- BackendEvent{
			Type:  Update,
			Key:   Key{Kind: "Handler", Namespace: "ns", Name: fmt.Sprintf("%d", i)},
			Value: &BackEndResource{},
		}
	}
	cancel()
	// Wait for the queue's run loop to end.
	time.Sleep(time.Millisecond)
	// Read the bufferred events.
	for i := 0; i < choutBufSize; i++ {
		ev, ok := <-q.chout
		if !ok {
			// Sometimes items less than 'choutBufSize' are stored into the queue, but that's
			// acceptable. That can happen due to goroutine scheduling.
			break
		}
		if ev.Name != fmt.Sprintf("%d", i) {
			t.Errorf("Got name %s Want %d", ev.Name, i)
		}
	}
	// After the buffer runs out, it should return an empty since it's closed due to cancel.

	if ev, ok := <-q.chout; ok {
		t.Errorf("Got %+v, Want empty", ev)
	}
}
<|endoftext|>


<commit_before>package privatemessage

import (
	"errors"
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/koding/bongo"
)

func fetchParticipantIds(participantNames []string) ([]int64, error) {
	participantIds := make([]int64, len(participantNames))
	for i, participantName := range participantNames {
		account, err := modelhelper.GetAccount(participantName)
		if err != nil {
			return nil, err
		}
		a := models.NewAccount()
		a.Id = account.SocialApiId
		a.OldId = account.Id.Hex()
		a.Nick = account.Profile.Nickname
		// fetch or create social api id
		if a.Id == 0 {
			if err := a.FetchOrCreate(); err != nil {
				return nil, err
			}
		}
		participantIds[i] = a.Id
	}

	return participantIds, nil
}

func appendCreatorIdIntoParticipantList(participants []int64, authorId int64) []int64 {
	for _, participant := range participants {
		if participant == authorId {
			return participants
		}
	}

	return append(participants, authorId)
}

func Init(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	cm := models.NewChannelMessage()
	cm.Body = req.Body
	participantIds, err := fetchParticipantIds(req.Recipients)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// append creator to the recipients
	participantIds = appendCreatorIdIntoParticipantList(participantIds, req.AccountId)

	// author and atleast one recipient should be in the
	// recipient list
	if len(participantIds) < 1 {
		// user can send private message to themself
		return response.NewBadRequest(errors.New("you should define your recipients"))
	}

	if req.GroupName == "" {
		req.GroupName = models.Channel_KODING_NAME
	}

	//// first create the channel
	c := models.NewPrivateMessageChannel(req.AccountId, req.GroupName)
	if err := c.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	messageContainer, err := cm.BuildEmptyMessageContainer()
	if err != nil {
		return response.NewBadRequest(err)
	}

	_, err = c.AddMessage(cm.Id)
	if err != nil {
		return response.NewBadRequest(err)
	}

	for _, participantId := range participantIds {
		_, err := c.AddParticipant(participantId)
		if err != nil {
			return response.NewBadRequest(err)
		}
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = c
	cmc.IsParticipant = true
	cmc.LastMessage = messageContainer
	cmc.ParticipantCount = len(participantIds)
	participantOldIds, err := models.FetchAccountOldsIdByIdsFromCache(participantIds)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cmc.ParticipantsPreview = participantOldIds

	return response.NewOK(cmc)
}

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	// check channel existence
	c := models.NewChannel()
	if err := c.ById(req.ChannelId); err != nil {
		return response.NewBadRequest(err)
	}

	// check if sender is whether a participant of conversation
	cp := models.NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = req.AccountId
	if err := cp.FetchParticipant(); err != nil {
		return response.NewBadRequest(err)
	}

	// add private message
	cm := models.NewChannelMessage()
	cm.Body = req.Body
	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	if _, err := c.AddMessage(cm.Id); err != nil {
		return response.NewBadRequest(err)
	}

	messageContainer, err := cm.BuildEmptyMessageContainer()
	if err != nil {
		return response.NewBadRequest(err)
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = c
	cmc.IsParticipant = true
	cmc.LastMessage = messageContainer

	return response.NewOK(cmc)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := request.GetQuery(u)

	if q.AccountId == 0 || q.GroupName == "" {
		return response.NewBadRequest(errors.New("request is not valid"))
	}

	channelList, err := getPrivateMessageChannels(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	if err := cc.Fetch(channelList, q); err != nil {
		return response.NewBadRequest(err)
	}

	cc.AddIsParticipant(q.AccountId)

	// TODO this should be in the channel cache by default
	cc.AddLastMessage()
	cc.AddUnreadCount(q.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func getPrivateMessageChannels(q *request.Query) ([]models.Channel, error) {
	// build query for
	c := models.NewChannel()
	channelIds := make([]int64, 0)
	query := bongo.B.DB.
		Model(c).
		Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE)

	// add exempt clause if needed
	if !q.ShowExempt {
		query = query.Where("api.channel.meta_bits = ?", models.Safe)
	}

	query = query.Limit(q.Limit).
		Offset(q.Skip).
		Order("api.channel.updated_at DESC")

	rows, err := query.Rows()
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	for rows.Next() {
		var channelId int64
		err := rows.Scan(&channelId)
		if err == nil {
			channelIds = append(channelIds, channelId)
		}
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<commit_msg>PrivateMessage: Check active participant before sending message<commit_after>package privatemessage

import (
	"errors"
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/koding/bongo"
)

func fetchParticipantIds(participantNames []string) ([]int64, error) {
	participantIds := make([]int64, len(participantNames))
	for i, participantName := range participantNames {
		account, err := modelhelper.GetAccount(participantName)
		if err != nil {
			return nil, err
		}
		a := models.NewAccount()
		a.Id = account.SocialApiId
		a.OldId = account.Id.Hex()
		a.Nick = account.Profile.Nickname
		// fetch or create social api id
		if a.Id == 0 {
			if err := a.FetchOrCreate(); err != nil {
				return nil, err
			}
		}
		participantIds[i] = a.Id
	}

	return participantIds, nil
}

func appendCreatorIdIntoParticipantList(participants []int64, authorId int64) []int64 {
	for _, participant := range participants {
		if participant == authorId {
			return participants
		}
	}

	return append(participants, authorId)
}

func Init(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	cm := models.NewChannelMessage()
	cm.Body = req.Body
	participantIds, err := fetchParticipantIds(req.Recipients)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// append creator to the recipients
	participantIds = appendCreatorIdIntoParticipantList(participantIds, req.AccountId)

	// author and atleast one recipient should be in the
	// recipient list
	if len(participantIds) < 1 {
		// user can send private message to themself
		return response.NewBadRequest(errors.New("you should define your recipients"))
	}

	if req.GroupName == "" {
		req.GroupName = models.Channel_KODING_NAME
	}

	//// first create the channel
	c := models.NewPrivateMessageChannel(req.AccountId, req.GroupName)
	if err := c.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	messageContainer, err := cm.BuildEmptyMessageContainer()
	if err != nil {
		return response.NewBadRequest(err)
	}

	_, err = c.AddMessage(cm.Id)
	if err != nil {
		return response.NewBadRequest(err)
	}

	for _, participantId := range participantIds {
		_, err := c.AddParticipant(participantId)
		if err != nil {
			return response.NewBadRequest(err)
		}
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = c
	cmc.IsParticipant = true
	cmc.LastMessage = messageContainer
	cmc.ParticipantCount = len(participantIds)
	participantOldIds, err := models.FetchAccountOldsIdByIdsFromCache(participantIds)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cmc.ParticipantsPreview = participantOldIds

	return response.NewOK(cmc)
}

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	// check channel existence
	c := models.NewChannel()
	if err := c.ById(req.ChannelId); err != nil {
		return response.NewBadRequest(err)
	}

	// check if sender is whether a participant of conversation
	cp := models.NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = req.AccountId
	if err := cp.FetchActiveParticipant(); err != nil {
		return response.NewBadRequest(err)
	}

	// add private message
	cm := models.NewChannelMessage()
	cm.Body = req.Body
	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	if _, err := c.AddMessage(cm.Id); err != nil {
		return response.NewBadRequest(err)
	}

	messageContainer, err := cm.BuildEmptyMessageContainer()
	if err != nil {
		return response.NewBadRequest(err)
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = c
	cmc.IsParticipant = true
	cmc.LastMessage = messageContainer

	return response.NewOK(cmc)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := request.GetQuery(u)

	if q.AccountId == 0 || q.GroupName == "" {
		return response.NewBadRequest(errors.New("request is not valid"))
	}

	channelList, err := getPrivateMessageChannels(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	if err := cc.Fetch(channelList, q); err != nil {
		return response.NewBadRequest(err)
	}

	cc.AddIsParticipant(q.AccountId)

	// TODO this should be in the channel cache by default
	cc.AddLastMessage()
	cc.AddUnreadCount(q.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func getPrivateMessageChannels(q *request.Query) ([]models.Channel, error) {
	// build query for
	c := models.NewChannel()
	channelIds := make([]int64, 0)
	query := bongo.B.DB.
		Model(c).
		Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE)

	// add exempt clause if needed
	if !q.ShowExempt {
		query = query.Where("api.channel.meta_bits = ?", models.Safe)
	}

	query = query.Limit(q.Limit).
		Offset(q.Skip).
		Order("api.channel.updated_at DESC")

	rows, err := query.Rows()
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	for rows.Next() {
		var channelId int64
		err := rows.Scan(&channelId)
		if err == nil {
			channelIds = append(channelIds, channelId)
		}
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<|endoftext|>


<commit_before>package vault

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"sync"

	"github.com/hashicorp/vault/logical"
)

const (
	// coreMountConfigPath is used to store the mount configuration.
	// Mounts are protected within the Vault itself, which means they
	// can only be viewed or modified after an unseal.
	coreMountConfigPath = "core/mounts"

	// backendBarrierPrefix is the prefix to the UUID used in the
	// barrier view for the backends.
	backendBarrierPrefix = "logical/"

	// systemBarrierPrefix is sthe prefix used for the
	// system logical backend.
	systemBarrierPrefix = "sys/"
)

var (
	// loadMountsFailed if loadMounts encounters an error
	loadMountsFailed = errors.New("failed to setup mount table")

	// protectedMounts cannot be remounted
	protectedMounts = []string{
		"audit/",
		"auth/",
		"sys/",
	}
)

// MountTable is used to represent the internal mount table
type MountTable struct {
	// This lock should be held whenever modifying the Entries field.
	sync.RWMutex

	Entries []*MountEntry `json:"entries"`
}

// Returns a deep copy of the mount table
func (t *MountTable) Clone() *MountTable {
	mt := &MountTable{
		Entries: make([]*MountEntry, len(t.Entries)),
	}
	for i, e := range t.Entries {
		mt.Entries[i] = e.Clone()
	}
	return mt
}

// MountEntry is used to represent a mount table entry
type MountEntry struct {
	Path        string            `json:"path"`        // Mount Path
	Type        string            `json:"type"`        // Logical backend Type
	Description string            `json:"description"` // User-provided description
	UUID        string            `json:"uuid"`        // Barrier view UUID
	Options     map[string]string `json:"options"`     // Backend configuration
}

// Returns a deep copy of the mount entry
func (e *MountEntry) Clone() *MountEntry {
	optClone := make(map[string]string)
	for k, v := range e.Options {
		optClone[k] = v
	}
	return &MountEntry{
		Path:        e.Path,
		Type:        e.Type,
		Description: e.Description,
		UUID:        e.UUID,
		Options:     optClone,
	}
}

// Mount is used to mount a new backend to the mount table.
func (c *Core) mount(me *MountEntry) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(me.Path, "/") {
		me.Path += "/"
	}

	// Prevent protected paths from being unmounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(me.Path, p) {
			return fmt.Errorf("cannot mount '%s'", me.Path)
		}
	}

	// Verify there is no conflicting mount
	if match := c.router.MatchingMount(me.Path); match != "" {
		return fmt.Errorf("existing mount at '%s'", match)
	}

	// Lookup the new backend
	backend, err := c.newLogicalBackend(me.Type, nil)
	if err != nil {
		return err
	}

	// Generate a new UUID and view
	me.UUID = generateUUID()
	view := NewBarrierView(c.barrier, backendBarrierPrefix+me.UUID+"/")

	// Update the mount table
	newTable := c.mounts.Clone()
	newTable.Entries = append(newTable.Entries, me)
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Mount the backend
	if err := c.router.Mount(backend, me.Path, view); err != nil {
		return err
	}
	c.logger.Printf("[INFO] core: mounted '%s' type: %s", me.Path, me.Type)
	return nil
}

// Unmount is used to unmount a path.
//
// TODO: document what happens to all secrets currently out for this path.
func (c *Core) unmount(path string) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(path, "/") {
		path += "/"
	}

	// Prevent protected paths from being unmounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(path, p) {
			return fmt.Errorf("cannot unmount '%s'", path)
		}
	}

	// Verify exact match of the route
	match := c.router.MatchingMount(path)
	if match == "" || path != match {
		return fmt.Errorf("no matching mount")
	}

	// Remove the entry from the mount table
	newTable := c.mounts.Clone()
	n := len(newTable.Entries)
	for i := 0; i < n; i++ {
		if newTable.Entries[i].Path == path {
			newTable.Entries[i], newTable.Entries[n-1] = newTable.Entries[n-1], nil
			newTable.Entries = newTable.Entries[:n-1]
			break
		}
	}

	// Update the mount table
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Unmount the backend
	if err := c.router.Unmount(path); err != nil {
		return err
	}

	// TODO: Delete data in view?
	// TODO: Handle revocation?
	c.logger.Printf("[INFO] core: unmounted '%s'", path)
	return nil
}

// Remount is used to remount a path at a new mount point.
func (c *Core) remount(src, dst string) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(src, "/") {
		src += "/"
	}
	if !strings.HasSuffix(dst, "/") {
		dst += "/"
	}

	// Prevent protected paths from being remounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(src, p) {
			return fmt.Errorf("cannot remount '%s'", src)
		}
	}

	// Verify exact match of the route
	match := c.router.MatchingMount(src)
	if match == "" || src != match {
		return fmt.Errorf("no matching mount at '%s'", src)
	}

	// Verify there is no conflicting mount
	if match := c.router.MatchingMount(dst); match != "" {
		return fmt.Errorf("existing mount at '%s'", match)
	}

	// Update the entry in the mount table
	newTable := c.mounts.Clone()
	for _, ent := range newTable.Entries {
		if ent.Path == src {
			ent.Path = dst
			break
		}
	}

	// Update the mount table
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Remount the backend
	if err := c.router.Remount(src, dst); err != nil {
		return err
	}
	c.logger.Printf("[INFO] core: remounted '%s' to '%s'", src, dst)
	return nil
}

// loadMounts is invoked as part of postUnseal to load the mount table
func (c *Core) loadMounts() error {
	// Load the existing mount table
	raw, err := c.barrier.Get(coreMountConfigPath)
	if err != nil {
		c.logger.Printf("[ERR] core: failed to read mount table: %v", err)
		return loadMountsFailed
	}
	if raw != nil {
		c.mounts = &MountTable{}
		if err := json.Unmarshal(raw.Value, c.mounts); err != nil {
			c.logger.Printf("[ERR] core: failed to decode mount table: %v", err)
			return loadMountsFailed
		}
	}

	// Done if we have restored the mount table
	if c.mounts != nil {
		return nil
	}

	// Create and persist the default mount table
	c.mounts = defaultMountTable()
	if err := c.persistMounts(c.mounts); err != nil {
		return loadMountsFailed
	}
	return nil
}

// persistMounts is used to persist the mount table after modification
func (c *Core) persistMounts(table *MountTable) error {
	// Marshal the table
	raw, err := json.Marshal(table)
	if err != nil {
		c.logger.Printf("[ERR] core: failed to encode mount table: %v", err)
		return err
	}

	// Create an entry
	entry := &Entry{
		Key:   coreMountConfigPath,
		Value: raw,
	}

	// Write to the physical backend
	if err := c.barrier.Put(entry); err != nil {
		c.logger.Printf("[ERR] core: failed to persist mount table: %v", err)
		return err
	}
	return nil
}

// setupMounts is invoked after we've loaded the mount table to
// initialize the logical backends and setup the router
func (c *Core) setupMounts() error {
	var backend logical.Backend
	var view *BarrierView
	var err error
	for _, entry := range c.mounts.Entries {
		// Initialize the backend, special casing for system
		barrierPrefix := backendBarrierPrefix
		if entry.Type == "system" {
			barrierPrefix = systemBarrierPrefix
		}

		backend, err = c.newLogicalBackend(entry.Type, nil)
		if err != nil {
			c.logger.Printf(
				"[ERR] core: failed to create mount entry %#v: %v",
				entry, err)
			return loadMountsFailed
		}

		// Create a barrier view using the UUID
		view = NewBarrierView(c.barrier, barrierPrefix+entry.UUID+"/")

		if entry.Type == "system" {
			c.systemView = view
		}

		// Mount the backend
		err = c.router.Mount(backend, entry.Path, view)
		if err != nil {
			c.logger.Printf("[ERR] core: failed to mount entry %#v: %v", entry, err)
			return loadMountsFailed
		}
	}
	return nil
}

// unloadMounts is used before we seal the vault to reset the mounts to
// their unloaded state. This is reversed by load and setup mounts.
func (c *Core) unloadMounts() error {
	c.mounts = nil
	c.router = NewRouter()
	c.systemView = nil
	return nil
}

// newLogicalBackend is used to create and configure a new logical backend by name
func (c *Core) newLogicalBackend(t string, conf map[string]string) (logical.Backend, error) {
	f, ok := c.logicalBackends[t]
	if !ok {
		return nil, fmt.Errorf("unknown backend type: %s", t)
	}

	return f(conf)
}

// defaultMountTable creates a default mount table
func defaultMountTable() *MountTable {
	table := &MountTable{}
	genericMount := &MountEntry{
		Path:        "secret/",
		Type:        "generic",
		Description: "generic secret storage",
		UUID:        generateUUID(),
	}
	sysMount := &MountEntry{
		Path:        "sys/",
		Type:        "system",
		Description: "system endpoints used for control, policy and debugging",
		UUID:        generateUUID(),
	}
	table.Entries = append(table.Entries, genericMount)
	table.Entries = append(table.Entries, sysMount)
	return table
}
<commit_msg>vault: Prevent UUID injection on sys mount path<commit_after>package vault

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"sync"

	"github.com/hashicorp/vault/logical"
)

const (
	// coreMountConfigPath is used to store the mount configuration.
	// Mounts are protected within the Vault itself, which means they
	// can only be viewed or modified after an unseal.
	coreMountConfigPath = "core/mounts"

	// backendBarrierPrefix is the prefix to the UUID used in the
	// barrier view for the backends.
	backendBarrierPrefix = "logical/"

	// systemBarrierPrefix is sthe prefix used for the
	// system logical backend.
	systemBarrierPrefix = "sys/"
)

var (
	// loadMountsFailed if loadMounts encounters an error
	loadMountsFailed = errors.New("failed to setup mount table")

	// protectedMounts cannot be remounted
	protectedMounts = []string{
		"audit/",
		"auth/",
		"sys/",
	}
)

// MountTable is used to represent the internal mount table
type MountTable struct {
	// This lock should be held whenever modifying the Entries field.
	sync.RWMutex

	Entries []*MountEntry `json:"entries"`
}

// Returns a deep copy of the mount table
func (t *MountTable) Clone() *MountTable {
	mt := &MountTable{
		Entries: make([]*MountEntry, len(t.Entries)),
	}
	for i, e := range t.Entries {
		mt.Entries[i] = e.Clone()
	}
	return mt
}

// MountEntry is used to represent a mount table entry
type MountEntry struct {
	Path        string            `json:"path"`        // Mount Path
	Type        string            `json:"type"`        // Logical backend Type
	Description string            `json:"description"` // User-provided description
	UUID        string            `json:"uuid"`        // Barrier view UUID
	Options     map[string]string `json:"options"`     // Backend configuration
}

// Returns a deep copy of the mount entry
func (e *MountEntry) Clone() *MountEntry {
	optClone := make(map[string]string)
	for k, v := range e.Options {
		optClone[k] = v
	}
	return &MountEntry{
		Path:        e.Path,
		Type:        e.Type,
		Description: e.Description,
		UUID:        e.UUID,
		Options:     optClone,
	}
}

// Mount is used to mount a new backend to the mount table.
func (c *Core) mount(me *MountEntry) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(me.Path, "/") {
		me.Path += "/"
	}

	// Prevent protected paths from being unmounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(me.Path, p) {
			return fmt.Errorf("cannot mount '%s'", me.Path)
		}
	}

	// Verify there is no conflicting mount
	if match := c.router.MatchingMount(me.Path); match != "" {
		return fmt.Errorf("existing mount at '%s'", match)
	}

	// Lookup the new backend
	backend, err := c.newLogicalBackend(me.Type, nil)
	if err != nil {
		return err
	}

	// Generate a new UUID and view
	me.UUID = generateUUID()
	view := NewBarrierView(c.barrier, backendBarrierPrefix+me.UUID+"/")

	// Update the mount table
	newTable := c.mounts.Clone()
	newTable.Entries = append(newTable.Entries, me)
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Mount the backend
	if err := c.router.Mount(backend, me.Path, view); err != nil {
		return err
	}
	c.logger.Printf("[INFO] core: mounted '%s' type: %s", me.Path, me.Type)
	return nil
}

// Unmount is used to unmount a path.
//
// TODO: document what happens to all secrets currently out for this path.
func (c *Core) unmount(path string) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(path, "/") {
		path += "/"
	}

	// Prevent protected paths from being unmounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(path, p) {
			return fmt.Errorf("cannot unmount '%s'", path)
		}
	}

	// Verify exact match of the route
	match := c.router.MatchingMount(path)
	if match == "" || path != match {
		return fmt.Errorf("no matching mount")
	}

	// Remove the entry from the mount table
	newTable := c.mounts.Clone()
	n := len(newTable.Entries)
	for i := 0; i < n; i++ {
		if newTable.Entries[i].Path == path {
			newTable.Entries[i], newTable.Entries[n-1] = newTable.Entries[n-1], nil
			newTable.Entries = newTable.Entries[:n-1]
			break
		}
	}

	// Update the mount table
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Unmount the backend
	if err := c.router.Unmount(path); err != nil {
		return err
	}

	// TODO: Delete data in view?
	// TODO: Handle revocation?
	c.logger.Printf("[INFO] core: unmounted '%s'", path)
	return nil
}

// Remount is used to remount a path at a new mount point.
func (c *Core) remount(src, dst string) error {
	c.mounts.Lock()
	defer c.mounts.Unlock()

	// Ensure we end the path in a slash
	if !strings.HasSuffix(src, "/") {
		src += "/"
	}
	if !strings.HasSuffix(dst, "/") {
		dst += "/"
	}

	// Prevent protected paths from being remounted
	for _, p := range protectedMounts {
		if strings.HasPrefix(src, p) {
			return fmt.Errorf("cannot remount '%s'", src)
		}
	}

	// Verify exact match of the route
	match := c.router.MatchingMount(src)
	if match == "" || src != match {
		return fmt.Errorf("no matching mount at '%s'", src)
	}

	// Verify there is no conflicting mount
	if match := c.router.MatchingMount(dst); match != "" {
		return fmt.Errorf("existing mount at '%s'", match)
	}

	// Update the entry in the mount table
	newTable := c.mounts.Clone()
	for _, ent := range newTable.Entries {
		if ent.Path == src {
			ent.Path = dst
			break
		}
	}

	// Update the mount table
	if err := c.persistMounts(newTable); err != nil {
		return errors.New("failed to update mount table")
	}
	c.mounts = newTable

	// Remount the backend
	if err := c.router.Remount(src, dst); err != nil {
		return err
	}
	c.logger.Printf("[INFO] core: remounted '%s' to '%s'", src, dst)
	return nil
}

// loadMounts is invoked as part of postUnseal to load the mount table
func (c *Core) loadMounts() error {
	// Load the existing mount table
	raw, err := c.barrier.Get(coreMountConfigPath)
	if err != nil {
		c.logger.Printf("[ERR] core: failed to read mount table: %v", err)
		return loadMountsFailed
	}
	if raw != nil {
		c.mounts = &MountTable{}
		if err := json.Unmarshal(raw.Value, c.mounts); err != nil {
			c.logger.Printf("[ERR] core: failed to decode mount table: %v", err)
			return loadMountsFailed
		}
	}

	// Done if we have restored the mount table
	if c.mounts != nil {
		return nil
	}

	// Create and persist the default mount table
	c.mounts = defaultMountTable()
	if err := c.persistMounts(c.mounts); err != nil {
		return loadMountsFailed
	}
	return nil
}

// persistMounts is used to persist the mount table after modification
func (c *Core) persistMounts(table *MountTable) error {
	// Marshal the table
	raw, err := json.Marshal(table)
	if err != nil {
		c.logger.Printf("[ERR] core: failed to encode mount table: %v", err)
		return err
	}

	// Create an entry
	entry := &Entry{
		Key:   coreMountConfigPath,
		Value: raw,
	}

	// Write to the physical backend
	if err := c.barrier.Put(entry); err != nil {
		c.logger.Printf("[ERR] core: failed to persist mount table: %v", err)
		return err
	}
	return nil
}

// setupMounts is invoked after we've loaded the mount table to
// initialize the logical backends and setup the router
func (c *Core) setupMounts() error {
	var backend logical.Backend
	var view *BarrierView
	var err error
	for _, entry := range c.mounts.Entries {
		// Initialize the backend, special casing for system
		barrierPath := backendBarrierPrefix + entry.UUID + "/"
		if entry.Type == "system" {
			barrierPath = systemBarrierPrefix
		}

		backend, err = c.newLogicalBackend(entry.Type, nil)
		if err != nil {
			c.logger.Printf(
				"[ERR] core: failed to create mount entry %#v: %v",
				entry, err)
			return loadMountsFailed
		}

		// Create a barrier view using the UUID
		view = NewBarrierView(c.barrier, barrierPath)

		if entry.Type == "system" {
			c.systemView = view
		}

		// Mount the backend
		err = c.router.Mount(backend, entry.Path, view)
		if err != nil {
			c.logger.Printf("[ERR] core: failed to mount entry %#v: %v", entry, err)
			return loadMountsFailed
		}
	}
	return nil
}

// unloadMounts is used before we seal the vault to reset the mounts to
// their unloaded state. This is reversed by load and setup mounts.
func (c *Core) unloadMounts() error {
	c.mounts = nil
	c.router = NewRouter()
	c.systemView = nil
	return nil
}

// newLogicalBackend is used to create and configure a new logical backend by name
func (c *Core) newLogicalBackend(t string, conf map[string]string) (logical.Backend, error) {
	f, ok := c.logicalBackends[t]
	if !ok {
		return nil, fmt.Errorf("unknown backend type: %s", t)
	}

	return f(conf)
}

// defaultMountTable creates a default mount table
func defaultMountTable() *MountTable {
	table := &MountTable{}
	genericMount := &MountEntry{
		Path:        "secret/",
		Type:        "generic",
		Description: "generic secret storage",
		UUID:        generateUUID(),
	}
	sysMount := &MountEntry{
		Path:        "sys/",
		Type:        "system",
		Description: "system endpoints used for control, policy and debugging",
		UUID:        generateUUID(),
	}
	table.Entries = append(table.Entries, genericMount)
	table.Entries = append(table.Entries, sysMount)
	return table
}
<|endoftext|>


<commit_before>package anteater

import (
	"time"
	"runtime"
	"sort"
	"sync/atomic"
	"fmt"
)

var FiveSecondsCounters []*StateHttpCounters = make([]*StateHttpCounters, 60)
var FiveSecondsCursor int

type State struct {
	Main  *StateMain
	Files *StateFiles
	Counters *StateHttpCounters
	CountersLast5Seconds *StateHttpCounters
	CountersLastMinute   *StateHttpCounters
	CountersLast5Minutes *StateHttpCounters
	Alloc *StateAllocateCounters
}

type StateMain struct {
	Time          int64
	StartTime     int64
	Goroutines    int
	MemoryUsage   uint64
	LastDump      int64
	LastDumpTime  int64
	IndexFileSize int64
}

type StateFiles struct {
	ContainersCount int
	FilesCount      int64
	FilesSize       int64
	SpacesCount    int64
	SpacesSize     int64
}

type StateHttpCounters struct {
	Get      int64
	Add      int64
	Delete   int64
	NotFound int64
}

type StateAllocateCounters struct {
	ReplaceSpace int64
	AddToSpace   int64
	ToEnd        int64
}

func init() {
	FiveSecondsTick()
	go func() {
		ch := time.Tick(5 * time.Second)
		for _ = range ch {
			func () {
				FiveSecondsTick()
			}()
		}
	}()
}

func GetState() *State {
	ms := &runtime.MemStats{}
	runtime.ReadMemStats(ms)
	m := &StateMain{
		Time         : time.Now().Unix(),
		StartTime    : StartTime.Unix(),
		Goroutines   : runtime.NumGoroutine(),
		MemoryUsage  : ms.TotalAlloc,
		LastDump     : LastDump.Unix(),
		LastDumpTime : LastDumpTime,
		IndexFileSize: IndexFileSize,
	}

	GetFileLock.Lock()
	defer GetFileLock.Unlock()

	var ids []int = make([]int, 0)
	for _, cn := range(FileContainers) {
		ids = append(ids, int(cn.Id))
	}
	sort.Ints(ids)
	var cnt *Container

	var totalSize, totalFileSize, fileCount, spacesCount, spacesTotalSize int64

	for _, id := range(ids) {
		cnt = FileContainers[int32(id)]
		_, sc, st := cnt.Spaces.ToHtml(10, cnt.Size)
		totalSize += cnt.Size
		fileCount += cnt.Count
		spacesCount += sc
		spacesTotalSize += st
		allocated := cnt.Size - (cnt.Size - cnt.Offset) - st
		totalFileSize += allocated
	}

	f := &StateFiles{
		ContainersCount : len(ids),
		FilesCount      : fileCount,
		FilesSize       : totalFileSize,
		SpacesCount     : spacesCount,
		SpacesSize      : spacesTotalSize,
	}

	return &State{
		Main     : m,
		Files    : f,
		Counters : HttpCn,
		CountersLast5Seconds : GetHttpStateByPeriod(1),
		CountersLastMinute : GetHttpStateByPeriod(12),
		CountersLast5Minutes : GetHttpStateByPeriod(60),
		Alloc    : AllocCn,
	}
}

func FiveSecondsTick() {
	if FiveSecondsCursor == 60 {
		FiveSecondsCursor = 0
	}
	if FiveSecondsCounters[FiveSecondsCursor] == nil {
		FiveSecondsCounters[FiveSecondsCursor] = &StateHttpCounters{}
	}
	FiveSecondsCounters[FiveSecondsCursor].SetData(HttpCn)
	FiveSecondsCursor++

	for k, v := range(FiveSecondsCounters) {
		if v != nil {
			fmt.Println(k, v)
		}
	}
}

func GetHttpStateByPeriod(period int) (result *StateHttpCounters) {
	curCursor := FiveSecondsCursor - 1
	diffCursor := curCursor
	result = &StateHttpCounters{}
	i := 0
	for {
		diffCursor--
		i++
		if diffCursor == -1 {
			diffCursor = 59
		}
		if FiveSecondsCounters[diffCursor] == nil {
			diffCursor++
			if diffCursor == 60 {
				diffCursor = 0
			}
			break
		}
		if i >= period {
			break
		}
	}
	//fmt.Println(period, curCursor, diffCursor)
	cur  := FiveSecondsCounters[curCursor]
	diff := FiveSecondsCounters[diffCursor]

	result.Add = cur.Add - diff.Add
	result.Get = cur.Get - diff.Add
	result.Delete = cur.Delete - diff.Delete
	result.NotFound = cur.NotFound - diff.NotFound
	return
}

func (s *StateHttpCounters) CGet() {
	atomic.AddInt64(&s.Get, 1)
}

func (s *StateHttpCounters) CAdd() {
	atomic.AddInt64(&s.Add, 1)
}

func (s *StateHttpCounters) CDelete() {
	atomic.AddInt64(&s.Delete, 1)
}

func (s *StateHttpCounters) CNotFound() {
	atomic.AddInt64(&s.NotFound, 1)
}

func (s *StateHttpCounters) SetData(otherS *StateHttpCounters) {
	s.Get = otherS.Get
	s.Add = otherS.Add
	s.Delete = otherS.Delete
	s.NotFound = otherS.NotFound
}

func (s *StateAllocateCounters) CTarget(target int) {
	switch target {
		case TARGET_SPACE_EQ:
			atomic.AddInt64(&s.ReplaceSpace, 1)
		case TARGET_SPACE_FREE:
			atomic.AddInt64(&s.AddToSpace, 1)
	 	case TARGET_NEW:
	 		atomic.AddInt64(&s.ToEnd, 1)
	}
}
<commit_msg>Debug<commit_after>package anteater

import (
	"time"
	"runtime"
	"sort"
	"sync/atomic"
	"fmt"
)

var FiveSecondsCounters []*StateHttpCounters = make([]*StateHttpCounters, 60)
var FiveSecondsCursor int

type State struct {
	Main  *StateMain
	Files *StateFiles
	Counters *StateHttpCounters
	CountersLast5Seconds *StateHttpCounters
	CountersLastMinute   *StateHttpCounters
	CountersLast5Minutes *StateHttpCounters
	Alloc *StateAllocateCounters
}

type StateMain struct {
	Time          int64
	StartTime     int64
	Goroutines    int
	MemoryUsage   uint64
	LastDump      int64
	LastDumpTime  int64
	IndexFileSize int64
}

type StateFiles struct {
	ContainersCount int
	FilesCount      int64
	FilesSize       int64
	SpacesCount    int64
	SpacesSize     int64
}

type StateHttpCounters struct {
	Get      int64
	Add      int64
	Delete   int64
	NotFound int64
}

type StateAllocateCounters struct {
	ReplaceSpace int64
	AddToSpace   int64
	ToEnd        int64
}

func init() {
	FiveSecondsTick()
	go func() {
		ch := time.Tick(5 * time.Second)
		for _ = range ch {
			func () {
				FiveSecondsTick()
			}()
		}
	}()
}

func GetState() *State {
	ms := &runtime.MemStats{}
	runtime.ReadMemStats(ms)
	m := &StateMain{
		Time         : time.Now().Unix(),
		StartTime    : StartTime.Unix(),
		Goroutines   : runtime.NumGoroutine(),
		MemoryUsage  : ms.TotalAlloc,
		LastDump     : LastDump.Unix(),
		LastDumpTime : LastDumpTime,
		IndexFileSize: IndexFileSize,
	}

	GetFileLock.Lock()
	defer GetFileLock.Unlock()

	var ids []int = make([]int, 0)
	for _, cn := range(FileContainers) {
		ids = append(ids, int(cn.Id))
	}
	sort.Ints(ids)
	var cnt *Container

	var totalSize, totalFileSize, fileCount, spacesCount, spacesTotalSize int64

	for _, id := range(ids) {
		cnt = FileContainers[int32(id)]
		_, sc, st := cnt.Spaces.ToHtml(10, cnt.Size)
		totalSize += cnt.Size
		fileCount += cnt.Count
		spacesCount += sc
		spacesTotalSize += st
		allocated := cnt.Size - (cnt.Size - cnt.Offset) - st
		totalFileSize += allocated
	}

	f := &StateFiles{
		ContainersCount : len(ids),
		FilesCount      : fileCount,
		FilesSize       : totalFileSize,
		SpacesCount     : spacesCount,
		SpacesSize      : spacesTotalSize,
	}

	return &State{
		Main     : m,
		Files    : f,
		Counters : HttpCn,
		CountersLast5Seconds : GetHttpStateByPeriod(1),
		CountersLastMinute : GetHttpStateByPeriod(12),
		CountersLast5Minutes : GetHttpStateByPeriod(60),
		Alloc    : AllocCn,
	}
}

func FiveSecondsTick() {
	if FiveSecondsCursor == 60 {
		FiveSecondsCursor = 0
	}
	if FiveSecondsCounters[FiveSecondsCursor] == nil {
		FiveSecondsCounters[FiveSecondsCursor] = &StateHttpCounters{}
	}
	FiveSecondsCounters[FiveSecondsCursor].SetData(HttpCn)
	FiveSecondsCursor++

	for k, v := range(FiveSecondsCounters) {
		if v != nil {
			fmt.Println(k, v)
		}
	}
}

func GetHttpStateByPeriod(period int) (result *StateHttpCounters) {
	curCursor := FiveSecondsCursor - 1
	diffCursor := curCursor
	result = &StateHttpCounters{}
	i := 0
	for {
		diffCursor--
		i++
		if diffCursor == -1 {
			diffCursor = 59
		}
		if FiveSecondsCounters[diffCursor] == nil {
			diffCursor++
			if diffCursor == 60 {
				diffCursor = 0
			}
			break
		}
		if i >= period {
			break
		}
	}

	cur  := FiveSecondsCounters[curCursor]
	diff := FiveSecondsCounters[diffCursor]

	fmt.Println(period, curCursor, diffCursor, cur, diff)
	result.Add = cur.Add - diff.Add
	result.Get = cur.Get - diff.Add
	result.Delete = cur.Delete - diff.Delete
	result.NotFound = cur.NotFound - diff.NotFound
	return
}

func (s *StateHttpCounters) CGet() {
	atomic.AddInt64(&s.Get, 1)
}

func (s *StateHttpCounters) CAdd() {
	atomic.AddInt64(&s.Add, 1)
}

func (s *StateHttpCounters) CDelete() {
	atomic.AddInt64(&s.Delete, 1)
}

func (s *StateHttpCounters) CNotFound() {
	atomic.AddInt64(&s.NotFound, 1)
}

func (s *StateHttpCounters) SetData(otherS *StateHttpCounters) {
	s.Get = otherS.Get
	s.Add = otherS.Add
	s.Delete = otherS.Delete
	s.NotFound = otherS.NotFound
}

func (s *StateAllocateCounters) CTarget(target int) {
	switch target {
		case TARGET_SPACE_EQ:
			atomic.AddInt64(&s.ReplaceSpace, 1)
		case TARGET_SPACE_FREE:
			atomic.AddInt64(&s.AddToSpace, 1)
	 	case TARGET_NEW:
	 		atomic.AddInt64(&s.ToEnd, 1)
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright 2017 Yannick Roffin
 *
 *   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 collect

import (
	"net/http"
	"sync"

	"gopkg.in/mgo.v2/bson"

	"github.com/labstack/echo"
	"github.com/yroffin/jarvis-go-ext/server/service/mongodb"
	"github.com/yroffin/jarvis-go-ext/server/types"
)

// MongodbService struct
type CollectService struct {
	mongoMiddleware *mongodb.MongoDriver
}

var instance *CollectService
var once sync.Once

// GetInstance : singleton instance
func GetInstance() *CollectService {
	once.Do(func() {
		instance = new(CollectService)
		instance.init()
	})
	return instance
}

// Get return all local collect
func (that *CollectService) GetAll(c echo.Context) error {
	var m *types.CollectResource
	m = new(types.CollectResource)
	c.Bind(&m)

	// retrieve all collections stored in "collect" database
	var names, err = that.mongoMiddleware.GetCollections("collect")
	if err != nil {
		return c.JSON(http.StatusBadRequest, err)
	}

	// reduce this collection by removing system.indexes
	var reduce = make([]string, len(names))
	var counter = 0
	for index := 1; index < len(names); index++ {
		if names[index] != "system.indexes" {
			reduce[counter] = names[index]
			counter++
		}
	}

	var result = make([]string, counter)
	copy(result, reduce[0:counter])

	// result
	m.Collections = result

	return c.JSON(http.StatusOK, m)
}

// Get all collection elements
func (that *CollectService) Get(c echo.Context) error {
	var m *types.CollectResource
	m = new(types.CollectResource)
	c.Bind(&m)

	if c.Param("id") == "" {
		// result
		var names, err = that.findAll()
		if err != nil {
			return c.JSON(http.StatusBadRequest, err)
		}
		m.Collections = names
	} else {
		// result
		var names, err = that.get(c.Param("id"))
		if err != nil {
			return c.JSON(http.StatusBadRequest, err)
		}
		m.Data = names
	}

	return c.JSON(http.StatusOK, m)
}

// findAll find all collection name in database
func (that *CollectService) findAll() ([]string, error) {
	// retrieve all collections stored in "collect" database
	var names, err = that.mongoMiddleware.GetCollections("collect")
	if err != nil {
		return nil, err
	}

	// reduce this collection by removing system.indexes
	var reduce = make([]string, len(names))
	var counter = 0
	for index := 1; index < len(names); index++ {
		if names[index] != "system.indexes" {
			reduce[counter] = names[index]
			counter++
		}
	}

	var result = make([]string, counter)
	copy(result, reduce[0:counter])
	return result, nil
}

// findAll find all collection name in database
func (that *CollectService) get(name string) ([]bson.M, error) {
	// retrieve all collections stored in "collect" database
	tuples := []bson.M{}
	that.mongoMiddleware.GetCollection("collect", name).Find(bson.M{}).All(&tuples)
	return tuples, nil
}

// init initialize service
func (that *CollectService) init() error {
	that.mongoMiddleware = mongodb.GetInstance()
	return nil
}
<commit_msg>trie des données<commit_after>/**
 * Copyright 2017 Yannick Roffin
 *
 *   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 collect

import (
	"net/http"
	"sync"

	"gopkg.in/mgo.v2/bson"

	"github.com/labstack/echo"
	"github.com/yroffin/jarvis-go-ext/server/service/mongodb"
	"github.com/yroffin/jarvis-go-ext/server/types"
)

// MongodbService struct
type CollectService struct {
	mongoMiddleware *mongodb.MongoDriver
}

var instance *CollectService
var once sync.Once

// GetInstance : singleton instance
func GetInstance() *CollectService {
	once.Do(func() {
		instance = new(CollectService)
		instance.init()
	})
	return instance
}

// Get return all local collect
func (that *CollectService) GetAll(c echo.Context) error {
	var m *types.CollectResource
	m = new(types.CollectResource)
	c.Bind(&m)

	// retrieve all collections stored in "collect" database
	var names, err = that.mongoMiddleware.GetCollections("collect")
	if err != nil {
		return c.JSON(http.StatusBadRequest, err)
	}

	// reduce this collection by removing system.indexes
	var reduce = make([]string, len(names))
	var counter = 0
	for index := 1; index < len(names); index++ {
		if names[index] != "system.indexes" {
			reduce[counter] = names[index]
			counter++
		}
	}

	var result = make([]string, counter)
	copy(result, reduce[0:counter])

	// result
	m.Collections = result

	return c.JSON(http.StatusOK, m)
}

// Get all collection elements
func (that *CollectService) Get(c echo.Context) error {
	var m *types.CollectResource
	m = new(types.CollectResource)
	c.Bind(&m)

	if c.Param("id") == "" {
		// result
		var names, err = that.findAll()
		if err != nil {
			return c.JSON(http.StatusBadRequest, err)
		}
		m.Collections = names
	} else {
		// result
		if c.QueryParam("orderby") == "" {
			var names, err = that.get(c.Param("id"))
			if err != nil {
				return c.JSON(http.StatusBadRequest, err)
			}
			m.Data = names
		} else {
			var names, err = that.getAndSort(c.Param("id"), c.QueryParam("orderby"))
			if err != nil {
				return c.JSON(http.StatusBadRequest, err)
			}
			m.Data = names
		}
	}

	return c.JSON(http.StatusOK, m)
}

// findAll find all collection name in database
func (that *CollectService) findAll() ([]string, error) {
	// retrieve all collections stored in "collect" database
	var names, err = that.mongoMiddleware.GetCollections("collect")
	if err != nil {
		return nil, err
	}

	// reduce this collection by removing system.indexes
	var reduce = make([]string, len(names))
	var counter = 0
	for index := 1; index < len(names); index++ {
		if names[index] != "system.indexes" {
			reduce[counter] = names[index]
			counter++
		}
	}

	var result = make([]string, counter)
	copy(result, reduce[0:counter])
	return result, nil
}

// findAll find all collection name in database
func (that *CollectService) get(name string) ([]bson.M, error) {
	// retrieve all collections stored in "collect" database
	tuples := []bson.M{}
	that.mongoMiddleware.GetCollection("collect", name).Find(bson.M{}).All(&tuples)
	return tuples, nil
}

// findAll find all collection name in database
func (that *CollectService) getAndSort(name string, sort string) ([]bson.M, error) {
	// retrieve all collections stored in "collect" database
	tuples := []bson.M{}
	that.mongoMiddleware.GetCollection("collect", name).Find(bson.M{}).Sort(sort).All(&tuples)
	return tuples, nil
}

// init initialize service
func (that *CollectService) init() error {
	that.mongoMiddleware = mongodb.GetInstance()
	return nil
}
<|endoftext|>


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

package utils

import (
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	h "github.com/open-falcon/falcon-plus/modules/api/app/helper"
	"github.com/spf13/viper"
)

func AuthSessionMidd(c *gin.Context) {
	auth, err := h.SessionChecking(c)
	if !viper.GetBool("skip_auth") {
		if err != nil || auth != true {
			log.Debugf("error: %v, auth: %v", err.Error(), auth)
			c.Set("auth", auth)
			h.JSONR(c, http.StatusUnauthorized, err)
			c.Abort()
			return
		}
	}
	c.Set("auth", auth)
}

func CORS() gin.HandlerFunc {
	return func(context *gin.Context) {
		context.Writer.Header().Add("Access-Control-Allow-Origin", "*")
		context.Writer.Header().Set("Access-Control-Max-Age", "86400")
		context.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH")
		context.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Apitoken")
		context.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
		context.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		if context.Request.Method == "OPTIONS" {
			context.AbortWithStatus(200)
		} else {
			context.Next()
		}
	}
}
<commit_msg>compatible with grafana5.4.3 (#690)<commit_after>// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package utils

import (
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	h "github.com/open-falcon/falcon-plus/modules/api/app/helper"
	"github.com/spf13/viper"
)

func AuthSessionMidd(c *gin.Context) {
	auth, err := h.SessionChecking(c)
	if !viper.GetBool("skip_auth") {
		if err != nil || auth != true {
			log.Debugf("error: %v, auth: %v", err.Error(), auth)
			c.Set("auth", auth)
			h.JSONR(c, http.StatusUnauthorized, err)
			c.Abort()
			return
		}
	}
	c.Set("auth", auth)
}

func CORS() gin.HandlerFunc {
	return func(context *gin.Context) {
		context.Writer.Header().Add("Access-Control-Allow-Origin", context.Request.Header.Get("Origin"))
		context.Writer.Header().Set("Access-Control-Max-Age", "86400")
		context.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH")
		context.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Apitoken")
		context.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
		context.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		if context.Request.Method == "OPTIONS" {
			context.AbortWithStatus(200)
		} else {
			context.Next()
		}
	}
}
<|endoftext|>


<commit_before>package video

import "github.com/32bitkid/mpeg/util"
import "errors"

var ErrInvalidReservedBits = errors.New("invalid reserved bits")

type Slice struct {
	slice_start_code                  uint32 // 32 bslbf
	slice_vertical_position_extension uint32 // 3 uimsbf
	priority_breakpoint               uint32 // 7 uimsbf
	quantiser_scale_code              uint32 // 5 uimsbf
	intra_slice_flag                  bool   // 1 bslbf
	intra_slice                       bool   // 1 uimsbf
	extra_information                 []byte
	macroblocks                       []interface{}
}

func slice(br util.BitReader32) (*Slice, error) {

	var err error

	s := Slice{}

	s.slice_start_code, err = br.Read32(32)
	if err != nil {
		return nil, err
	}

	if false /* (vertical_size > 2800) */ {
		s.slice_vertical_position_extension, err = br.Read32(3)
		if err != nil {
			return nil, err
		}
	}

	if false /* (<sequence_scalable_extension() is present in the bitstream>) */ {
		if false /* (scalable_mode == “data partitioning” ) */ {
			s.priority_breakpoint, err = br.Read32(7)
			if err != nil {
				return nil, err
			}
		}
	}

	s.quantiser_scale_code, err = br.Read32(5)
	if err != nil {
		return nil, err
	}

	nextbits, err := br.Peek32(1)
	if err != nil {
		return nil, err
	}

	if nextbits == 1 {
		s.intra_slice_flag, err = br.ReadBit()
		if err != nil {
			return nil, err
		}

		s.intra_slice, err = br.ReadBit()
		if err != nil {
			return nil, err
		}

		reserved_bits, err := br.Read32(7)
		if err != nil {
			return nil, err
		}
		if reserved_bits != 0 {
			return nil, ErrInvalidReservedBits
		}

		for {
			nextbits, err = br.Peek32(1)
			if err != nil {
				return nil, err
			}
			if nextbits != 1 {
				break
			}
			err = br.Trash(1)
			if err != nil {
				return nil, err
			}
			data, err := br.Read32(8)
			if err != nil {
				return nil, err
			}
			s.extra_information = append(s.extra_information, byte(data))
		}
	}
	err = br.Trash(1)
	if err != nil {
		return nil, err
	}

	for {
		mb, err := macroblock(br)
		if err != nil {
			return nil, err
		}
		s.macroblocks = append(s.macroblocks, mb)

		nextbits, err = br.Peek32(23)
		if err != nil {
			return nil, err
		}

		if nextbits == 0 {
			break
		}

	}

	return &s, next_start_code(br)
}
<commit_msg>little cleanup<commit_after>package video

import "github.com/32bitkid/mpeg/util"
import "errors"

var ErrInvalidReservedBits = errors.New("invalid reserved bits")

type Slice struct {
	slice_start_code                  StartCode // 32 bslbf
	slice_vertical_position_extension uint32    // 3 uimsbf
	priority_breakpoint               uint32    // 7 uimsbf
	quantiser_scale_code              uint32    // 5 uimsbf
	intra_slice_flag                  bool      // 1 bslbf
	intra_slice                       bool      // 1 uimsbf
	extra_information                 []byte
	macroblocks                       []interface{}
}

func slice(br util.BitReader32) (*Slice, error) {

	s := Slice{}

	code, err := br.Read32(32)
	if err != nil {
		return nil, err
	}

	if is_slice_start_code(StartCode(code)) == false {
		return nil, ErrUnexpectedStartCode
	}

	s.slice_start_code = StartCode(code)

	if false /* (vertical_size > 2800) */ {
		s.slice_vertical_position_extension, err = br.Read32(3)
		if err != nil {
			return nil, err
		}
	}

	if false /* (<sequence_scalable_extension() is present in the bitstream>) */ {
		if false /* (scalable_mode == “data partitioning” ) */ {
			s.priority_breakpoint, err = br.Read32(7)
			if err != nil {
				return nil, err
			}
		}
	}

	s.quantiser_scale_code, err = br.Read32(5)
	if err != nil {
		return nil, err
	}

	nextbits, err := br.Peek32(1)
	if err != nil {
		return nil, err
	}

	if nextbits == 1 {
		s.intra_slice_flag, err = br.ReadBit()
		if err != nil {
			return nil, err
		}

		s.intra_slice, err = br.ReadBit()
		if err != nil {
			return nil, err
		}

		reserved_bits, err := br.Read32(7)
		if err != nil {
			return nil, err
		} else if reserved_bits != 0 {
			return nil, ErrInvalidReservedBits
		}

		for {
			nextbits, err = br.Peek32(1)
			if err != nil {
				return nil, err
			} else if nextbits != 1 {
				break
			}

			err = br.Trash(1)
			if err != nil {
				return nil, err
			}

			data, err := br.Read32(8)
			if err != nil {
				return nil, err
			}
			s.extra_information = append(s.extra_information, byte(data))
		}
	}

	err = br.Trash(1)
	if err != nil {
		return nil, err
	}

	for {
		mb, err := macroblock(br)
		if err != nil {
			return nil, err
		}
		s.macroblocks = append(s.macroblocks, mb)

		nextbits, err = br.Peek32(23)
		if err != nil {
			return nil, err
		}

		if nextbits == 0 {
			break
		}

	}

	return &s, next_start_code(br)
}
<|endoftext|>


<commit_before>package generate

import (
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"strings"
)

func writeConst(out io.Writer, fileSet *token.FileSet, n ast.Node) {
	// ast.Print(fileSet, n)
	// return
	viz := constVisitor{
		out:     out,
		fileSet: fileSet,
	}
	ast.Walk(&viz, n)
}

type constVisitor struct {
	out     io.Writer
	fileSet *token.FileSet
}

func (v *constVisitor) Visit(node ast.Node) ast.Visitor {

	switch n := node.(type) {
	case *ast.GenDecl:
		if n.Tok == token.CONST {
			fmt.Fprintf(v.out, "// %v\n", v.fileSet.Position(n.Pos()))

			var viz constDeclVisitor
			ast.Walk(&viz, n)

			done := make(map[string]struct{})
			for _, t := range viz.consts {
				if _, ok := done[t.constType]; !ok && t.constType != "" {
					fmt.Fprintf(v.out, "export type %v = string;\n", t.constType)
					done[t.constType] = struct{}{}
				}
			}
			fmt.Fprintf(v.out, "\n")
			writeConstSpecs(v.out, viz.consts)
			fmt.Fprintf(v.out, "\n")
		}
		return nil
	}
	return v
}

type ConstSpec struct {
	constName  string
	constType  string
	constValue string
}

type constDeclVisitor struct {
	consts   []ConstSpec
	lastType string
}

func (v *constDeclVisitor) Visit(node ast.Node) ast.Visitor {

	switch n := node.(type) {
	case *ast.ValueSpec:
		name := n.Names[0].String()
		if tv, ok := n.Type.(*ast.Ident); ok {
			v.lastType = tv.Name
		}
		if lv, ok := n.Values[0].(*ast.BasicLit); ok {
			if lv.Kind == token.STRING {
				if v.lastType == "" {
					v.lastType = "string"
				}
				v.consts = append(v.consts, ConstSpec{
					constName:  name,
					constType:  v.lastType,
					constValue: lv.Value,
				})
			}
		}

		return nil
	}
	return v
}

func writeConstSpecs(w io.Writer, consts []ConstSpec) {
	var nameWidth int
	for _, c := range consts {
		w := len(c.constName) + len(c.constType) + 1
		if w > nameWidth {
			nameWidth = w
		}
	}
	for _, c := range consts {
		fmt.Fprintf(w, "export const %s:%s%s = %s;\n",
			c.constName, c.constType, strings.Repeat(" ", nameWidth-len(c.constName)-len(c.constType)-1),
			c.constValue,
		)
	}
}
<commit_msg>Properly handle empty and string types.<commit_after>package generate

import (
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"strings"
)

func writeConst(out io.Writer, fileSet *token.FileSet, n ast.Node) {
	// ast.Print(fileSet, n)
	// return
	viz := constVisitor{
		out:     out,
		fileSet: fileSet,
	}
	ast.Walk(&viz, n)
}

type constVisitor struct {
	out     io.Writer
	fileSet *token.FileSet
}

func (v *constVisitor) Visit(node ast.Node) ast.Visitor {

	switch n := node.(type) {
	case *ast.GenDecl:
		if n.Tok == token.CONST {
			fmt.Fprintf(v.out, "// %v\n", v.fileSet.Position(n.Pos()))

			var viz constDeclVisitor
			ast.Walk(&viz, n)

			done := map[string]struct{}{"": struct{}{}, "string": struct{}{}}
			for _, t := range viz.consts {
				if _, ok := done[t.constType]; !ok {
					fmt.Fprintf(v.out, "export type %v = string;\n", t.constType)
					done[t.constType] = struct{}{}
				}
			}
			fmt.Fprintf(v.out, "\n")
			writeConstSpecs(v.out, viz.consts)
			fmt.Fprintf(v.out, "\n")
		}
		return nil
	}
	return v
}

type ConstSpec struct {
	constName  string
	constType  string
	constValue string
}

type constDeclVisitor struct {
	consts   []ConstSpec
	lastType string
}

func (v *constDeclVisitor) Visit(node ast.Node) ast.Visitor {

	switch n := node.(type) {
	case *ast.ValueSpec:
		name := n.Names[0].String()
		if tv, ok := n.Type.(*ast.Ident); ok {
			v.lastType = tv.Name
		}
		if lv, ok := n.Values[0].(*ast.BasicLit); ok {
			if lv.Kind == token.STRING {
				if v.lastType == "" {
					v.lastType = "string"
				}
				v.consts = append(v.consts, ConstSpec{
					constName:  name,
					constType:  v.lastType,
					constValue: lv.Value,
				})
			}
		}

		return nil
	}
	return v
}

func writeConstSpecs(w io.Writer, consts []ConstSpec) {
	var nameWidth int
	for _, c := range consts {
		w := len(c.constName) + len(c.constType) + 1
		if w > nameWidth {
			nameWidth = w
		}
	}
	for _, c := range consts {
		fmt.Fprintf(w, "export const %s:%s%s = %s;\n",
			c.constName, c.constType, strings.Repeat(" ", nameWidth-len(c.constName)-len(c.constType)-1),
			c.constValue,
		)
	}
}
<|endoftext|>