Example #1
0
// Unwraps a rpcError and returns the correct error type.
func unwrapError(rpcError *rpcError) error {
	if rpcError != nil {
		switch rpcError.Type {
		case "InternalServerError":
			return core.InternalServerError(rpcError.Value)
		case "NotSupportedError":
			return core.NotSupportedError(rpcError.Value)
		case "MalformedRequestError":
			return core.MalformedRequestError(rpcError.Value)
		case "UnauthorizedError":
			return core.UnauthorizedError(rpcError.Value)
		case "NotFoundError":
			return core.NotFoundError(rpcError.Value)
		case "SyntaxError":
			return core.SyntaxError(rpcError.Value)
		case "SignatureValidationError":
			return core.SignatureValidationError(rpcError.Value)
		case "CertificateIssuanceError":
			return core.CertificateIssuanceError(rpcError.Value)
		case "NoSuchRegistrationError":
			return core.NoSuchRegistrationError(rpcError.Value)
		case "TooManyRPCRequestsError":
			return core.TooManyRPCRequestsError(rpcError.Value)
		case "RateLimitedError":
			return core.RateLimitedError(rpcError.Value)
		case "ServiceUnavailableError":
			return core.ServiceUnavailableError(rpcError.Value)
		default:
			return errors.New(rpcError.Value)
		}
	}
	return nil
}
Example #2
0
// Unwraps a rpcError and returns the correct error type.
func unwrapError(rpcError rpcError) (err error) {
	if rpcError.Value != "" {
		switch rpcError.Type {
		case "InternalServerError":
			err = core.InternalServerError(rpcError.Value)
		case "NotSupportedError":
			err = core.NotSupportedError(rpcError.Value)
		case "MalformedRequestError":
			err = core.MalformedRequestError(rpcError.Value)
		case "UnauthorizedError":
			err = core.UnauthorizedError(rpcError.Value)
		case "NotFoundError":
			err = core.NotFoundError(rpcError.Value)
		case "SyntaxError":
			err = core.SyntaxError(rpcError.Value)
		case "SignatureValidationError":
			err = core.SignatureValidationError(rpcError.Value)
		case "CertificateIssuanceError":
			err = core.CertificateIssuanceError(rpcError.Value)
		case "NoSuchRegistrationError":
			err = core.NoSuchRegistrationError(rpcError.Value)
		case "TooManyRPCRequestsError":
			err = core.TooManyRPCRequestsError(rpcError.Value)
		case "RateLimitedError":
			err = core.RateLimitedError(rpcError.Value)
		default:
			err = errors.New(rpcError.Value)
		}
	}
	return
}
Example #3
0
// Unwraps a rpcError and returns the correct error type.
func unwrapError(rpcError *rpcError) error {
	if rpcError != nil {
		switch rpcError.Type {
		case "InternalServerError":
			return core.InternalServerError(rpcError.Value)
		case "NotSupportedError":
			return core.NotSupportedError(rpcError.Value)
		case "MalformedRequestError":
			return core.MalformedRequestError(rpcError.Value)
		case "UnauthorizedError":
			return core.UnauthorizedError(rpcError.Value)
		case "NotFoundError":
			return core.NotFoundError(rpcError.Value)
		case "SignatureValidationError":
			return core.SignatureValidationError(rpcError.Value)
		case "NoSuchRegistrationError":
			return core.NoSuchRegistrationError(rpcError.Value)
		case "TooManyRPCRequestsError":
			return core.TooManyRPCRequestsError(rpcError.Value)
		case "RateLimitedError":
			return core.RateLimitedError(rpcError.Value)
		default:
			if strings.HasPrefix(rpcError.Type, "urn:") {
				return &probs.ProblemDetails{
					Type:       probs.ProblemType(rpcError.Type),
					Detail:     rpcError.Value,
					HTTPStatus: rpcError.HTTPStatus,
				}
			}
			return errors.New(rpcError.Value)
		}
	}
	return nil
}
Example #4
0
// Start starts the AMQP-RPC server and handles reconnections, this will block
// until a fatal error is returned or AmqpRPCServer.Stop() is called and all
// remaining messages are processed.
func (rpc *AmqpRPCServer) Start(c *cmd.AMQPConfig) error {
	tooManyGoroutines := rpcResponse{
		Error: wrapError(core.TooManyRPCRequestsError("RPC server has spawned too many Goroutines")),
	}
	tooManyRequestsResponse, err := json.Marshal(tooManyGoroutines)
	if err != nil {
		return err
	}
	rpc.tooManyRequestsResponse = tooManyRequestsResponse

	err = rpc.connection.connect(c)
	if err != nil {
		return err
	}
	rpc.mu.Lock()
	rpc.connected = true
	rpc.mu.Unlock()

	go rpc.catchSignals()

	for {
		select {
		case msg, ok := <-rpc.connection.messages():
			if ok {
				rpc.stats.TimingDuration(fmt.Sprintf("RPC.MessageLag.%s", rpc.serverQueue), rpc.clk.Now().Sub(msg.Timestamp), 1.0)
				if rpc.maxConcurrentRPCServerRequests > 0 && atomic.LoadInt64(&rpc.currentGoroutines) >= rpc.maxConcurrentRPCServerRequests {
					rpc.replyTooManyRequests(msg)
					rpc.stats.Inc(fmt.Sprintf("RPC.CallsDropped.%s", rpc.serverQueue), 1, 1.0)
					break // this breaks the select, not the for
				}
				rpc.stats.Inc(fmt.Sprintf("RPC.Traffic.Rx.%s", rpc.serverQueue), int64(len(msg.Body)), 1.0)
				go func() {
					atomic.AddInt64(&rpc.currentGoroutines, 1)
					defer atomic.AddInt64(&rpc.currentGoroutines, -1)
					startedProcessing := rpc.clk.Now()
					if rpc.handleDelivery != nil {
						rpc.handleDelivery(msg)
					} else {
						rpc.processMessage(msg)
					}
					rpc.stats.TimingDuration(fmt.Sprintf("RPC.ServerProcessingLatency.%s", msg.Type), time.Since(startedProcessing), 1.0)
				}()
			} else {
				rpc.mu.RLock()
				if rpc.done {
					// chan has been closed by rpc.connection.Cancel
					rpc.log.Info(" [!] Finished processing messages")
					rpc.mu.RUnlock()
					return nil
				}
				rpc.mu.RUnlock()
				rpc.log.Info(" [!] Got channel close, but no signal to shut down. Continuing.")
			}
		case err = <-rpc.connection.closeChannel():
			rpc.log.Info(fmt.Sprintf(" [!] Server channel closed: %s", rpc.serverQueue))
			rpc.connection.reconnect(c, rpc.log)
		}
	}
}
Example #5
0
func TestWrapError(t *testing.T) {
	testCases := []error{
		core.InternalServerError("foo"),
		core.NotSupportedError("foo"),
		core.MalformedRequestError("foo"),
		core.UnauthorizedError("foo"),
		core.NotFoundError("foo"),
		core.SignatureValidationError("foo"),
		core.CertificateIssuanceError("foo"),
		core.NoSuchRegistrationError("foo"),
		core.RateLimitedError("foo"),
		core.TooManyRPCRequestsError("foo"),
		errors.New("foo"),
	}
	for _, c := range testCases {
		wrapped := wrapError(c)
		test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name())
		test.AssertEquals(t, wrapped.Value, "foo")
		unwrapped := unwrapError(wrapped)
		test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name())
		test.AssertEquals(t, unwrapped.Error(), "foo")
	}

	complicated := []struct {
		given    error
		expected error
	}{
		{
			&probs.ProblemDetails{
				Type:       probs.ConnectionProblem,
				Detail:     "whoops",
				HTTPStatus: 417,
			},
			&probs.ProblemDetails{
				Type:       probs.ConnectionProblem,
				Detail:     "whoops",
				HTTPStatus: 417,
			},
		},
		{
			&probs.ProblemDetails{Type: "invalid", Detail: "hm"},
			errors.New("hm"),
		},
		{
			errors.New(""),
			errors.New(""),
		},
	}
	for i, tc := range complicated {
		actual := unwrapError(wrapError(tc.given))
		if !reflect.DeepEqual(tc.expected, actual) {
			t.Errorf("rpc error wrapping case %d: want %#v, got %#v", i, tc.expected, actual)
		}

	}
}
Example #6
0
// Start starts the AMQP-RPC server and handles reconnections, this will block
// until a fatal error is returned or AmqpRPCServer.Stop() is called and all
// remaining messages are processed.
func (rpc *AmqpRPCServer) Start(c cmd.Config) error {
	tooManyGoroutines := rpcResponse{
		Error: wrapError(core.TooManyRPCRequestsError("RPC server has spawned too many Goroutines")),
	}
	tooManyRequestsResponse, err := json.Marshal(tooManyGoroutines)
	if err != nil {
		return err
	}
	rpc.tooManyRequestsResponse = tooManyRequestsResponse

	err = rpc.connection.connect(c)
	if err != nil {
		return err
	}
	rpc.mu.Lock()
	rpc.connected = true
	rpc.mu.Unlock()

	go rpc.catchSignals()

	for {
		select {
		case msg, ok := <-rpc.connection.messages():
			if ok {
				if rpc.maxConcurrentRPCServerRequests > 0 && atomic.LoadInt64(&rpc.currentGoroutines) >= rpc.maxConcurrentRPCServerRequests {
					rpc.replyTooManyRequests(msg)
					break // this breaks the select, not the for
				}
				go func() {
					atomic.AddInt64(&rpc.currentGoroutines, 1)
					defer atomic.AddInt64(&rpc.currentGoroutines, -1)
					rpc.processMessage(msg)
				}()
			} else {
				rpc.mu.RLock()
				if rpc.done {
					// chan has been closed by rpc.connection.Cancel
					rpc.log.Info(" [!] Finished processing messages")
					rpc.mu.RUnlock()
					return nil
				}
				rpc.mu.RUnlock()
				rpc.log.Info(" [!] Got channel close, but no signal to shut down. Continuing.")
			}
		case err = <-rpc.connection.closeChannel():
			rpc.log.Info(fmt.Sprintf(" [!] Server channel closed: %s", rpc.serverQueue))
			rpc.connection.reconnect(c, rpc.log)
		}
	}
}
Example #7
0
func TestWrapError(t *testing.T) {
	testCases := []error{
		core.InternalServerError("foo"),
		core.NotSupportedError("foo"),
		core.MalformedRequestError("foo"),
		core.UnauthorizedError("foo"),
		core.NotFoundError("foo"),
		core.SyntaxError("foo"),
		core.SignatureValidationError("foo"),
		core.CertificateIssuanceError("foo"),
		core.NoSuchRegistrationError("foo"),
		core.RateLimitedError("foo"),
		core.TooManyRPCRequestsError("foo"),
	}
	for _, c := range testCases {
		wrapped := wrapError(c)
		test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name())
		test.AssertEquals(t, wrapped.Value, "foo")
		unwrapped := unwrapError(wrapped)
		test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name())
		test.AssertEquals(t, unwrapped.Error(), "foo")
	}
}
Example #8
0
// Start starts the AMQP-RPC server and handles reconnections, this will block
// until a fatal error is returned or AmqpRPCServer.Stop() is called and all
// remaining messages are processed.
func (rpc *AmqpRPCServer) Start(c cmd.Config) error {
	tooManyGoroutines := rpcResponse{
		Error: wrapError(core.TooManyRPCRequestsError("RPC server has spawned too many Goroutines")),
	}
	tooManyRequestsResponse, err := json.Marshal(tooManyGoroutines)
	if err != nil {
		return err
	}
	rpc.tooManyRequestsResponse = tooManyRequestsResponse

	go rpc.catchSignals()
	for {
		rpc.dMu.Lock()
		if rpc.done {
			rpc.dMu.Unlock()
			break
		}
		rpc.dMu.Unlock()
		var err error
		rpc.Channel, err = AmqpChannel(c)
		if err != nil {
			return err
		}
		rpc.connectionHandler(rpc)

		msgs, err := amqpSubscribe(rpc.Channel, rpc.serverQueue, rpc.consumerName, rpc.log)
		if err != nil {
			return err
		}
		rpc.connected = true
		rpc.log.Info(" [!] Connected to AMQP")

		closeChan := rpc.Channel.NotifyClose(make(chan *amqp.Error, 1))
		for blocking := true; blocking; {
			select {
			case msg, ok := <-msgs:
				if ok {
					if rpc.maxConcurrentRPCServerRequests > 0 && atomic.LoadInt64(&rpc.currentGoroutines) >= rpc.maxConcurrentRPCServerRequests {
						rpc.replyTooManyRequests(msg)
						break // this breaks the select, not the for
					}
					go func() {
						atomic.AddInt64(&rpc.currentGoroutines, 1)
						defer atomic.AddInt64(&rpc.currentGoroutines, -1)
						rpc.processMessage(msg)
					}()
				} else {
					// chan has been closed by rpc.channel.Cancel
					rpc.log.Info(" [!] Finished processing messages")
					return nil
				}
			case err = <-closeChan:
				rpc.connected = false
				rpc.log.Warning(fmt.Sprintf(" [!] AMQP Channel closed, will reconnect in 5 seconds: [%s]", err))
				time.Sleep(time.Second * 5)
				blocking = false
			}
		}
	}
	return nil
}