<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package router

import (
	"io"

	"github.com/TheThingsNetwork/ttn/api"
	pb "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/core/router/gateway"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/spf13/viper"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

type routerRPC struct {
	router *router
}

var grpcErrf = grpc.Errorf // To make go vet stop complaining

func (r *routerRPC) gatewayFromContext(ctx context.Context) (gtw *gateway.Gateway, err error) {
	md, err := api.MetadataFromContext(ctx)
	if err != nil {
		return nil, err
	}

	gatewayID, err := api.IDFromMetadata(md)
	if err != nil {
		return nil, err
	}

	token, err := api.TokenFromMetadata(md)
	if err != nil {
		return nil, err
	}

	if !viper.GetBool("router.skip-verify-gateway-token") {
		claims, err := r.router.ValidateTTNAuthContext(ctx)
		if err != nil {
			return nil, err
		}
		if claims.Type != "gateway" || claims.Subject != gatewayID {
			return nil, errors.NewErrPermissionDenied("Gateway token not authorized")
		}
	}

	gtw = r.router.getGateway(gatewayID)
	gtw.SetToken(token)

	return gtw, nil
}

// GatewayStatus implements RouterServer interface (github.com/TheThingsNetwork/ttn/api/router)
func (r *routerRPC) GatewayStatus(stream pb.Router_GatewayStatusServer) error {
	gateway, err := r.gatewayFromContext(stream.Context())
	if err != nil {
		return errors.BuildGRPCError(err)
	}

	for {
		status, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&empty.Empty{})<commit_msg>Better handling of gateway errors<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package router

import (
	"fmt"
	"io"

	"github.com/TheThingsNetwork/go-account-lib/claims"
	"github.com/TheThingsNetwork/ttn/api"
	pb "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/core/router/gateway"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/spf13/viper"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

type routerRPC struct {
	router *router
}

var grpcErrf = grpc.Errorf // To make go vet stop complaining

func (r *routerRPC) gatewayFromContext(ctx context.Context) (gtw *gateway.Gateway, err error) {
	md, err := api.MetadataFromContext(ctx)
	if err != nil {
		return nil, err
	}

	gatewayID, err := api.IDFromMetadata(md)
	if err != nil {
		return nil, err
	}

	var token string

	if !viper.GetBool("router.skip-verify-gateway-token") {
		token, err = api.TokenFromMetadata(md)
		if err != nil {
			return nil, err
		}
		if token == "" {
			return nil, errors.NewErrPermissionDenied("No gateway token supplied")
		}
		if r.router.TokenKeyProvider == nil {
			return nil, errors.NewErrInternal("No token provider configured")
		}
		claims, err := claims.FromToken(r.router.TokenKeyProvider, token)
		if err != nil {
			return nil, errors.NewErrPermissionDenied(fmt.Sprintf("Gateway token invalid: %s", err.Error()))
		}
		if claims.Type != "gateway" || claims.Subject != gatewayID {
			return nil, errors.NewErrPermissionDenied("Gateway token not consistent")
		}
	}

	gtw = r.router.getGateway(gatewayID)
	gtw.SetToken(token)

	return gtw, nil
}

// GatewayStatus implements RouterServer interface (github.com/TheThingsNetwork/ttn/api/router)
func (r *routerRPC) GatewayStatus(stream pb.Router_GatewayStatusServer) error {
	gateway, err := r.gatewayFromContext(stream.Context())
	if err != nil {
		return errors.BuildGRPCError(err)
	}

	for {
		status, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&empty.Empty{})
{'fraction_non_alphanumeric': 0.12601419878296147, 'fraction_numerical': 0.0030425963488843813, 'mean_word_length': 4.204485488126649, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5409212', 'n_tokens_mistral': 1448, 'n_tokens_neox': 1354, 'n_words': 324}