summaryrefslogtreecommitdiffstats
path: root/jsonrpc2/jsonrpc2.go
blob: 4e853d5b5682515ebec5a332ee08f2d802d7b9de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright 2018 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 jsonrpc2 is a minimal implementation of the JSON RPC 2 spec.
// https://www.jsonrpc.org/specification
// It is intended to be compatible with other implementations at the wire level.
package jsonrpc2

import (
	"context"
	"errors"
)

var (
	// ErrIdleTimeout is returned when serving timed out waiting for new connections.
	ErrIdleTimeout = errors.New("timed out waiting for new connections")
	// ErrNotHandled is returned from a handler to indicate it did not handle the
	// message.
	ErrNotHandled = errors.New("JSON RPC not handled")
	// ErrAsyncResponse is returned from a handler to indicate it will generate a
	// response asynchronously.
	ErrAsyncResponse = errors.New("JSON RPC asynchronous response")
)

// Preempter handles messages on a connection before they are queued to the main
// handler.
// Primarily this is used for cancel handlers or notifications for which out of
// order processing is not an issue.
type Preempter interface {
	// Preempt is invoked for each incoming request before it is queued.
	// If the request is a call, it must return a value or an error for the reply.
	// Preempt should not block or start any new messages on the connection.
	Preempt(ctx context.Context, req *Request) (interface{}, error)
}

// Handler handles messages on a connection.
type Handler interface {
	// Handle is invoked for each incoming request.
	// If the request is a call, it must return a value or an error for the reply.
	Handle(ctx context.Context, req *Request) (interface{}, error)
}

type defaultHandler struct{}

func (defaultHandler) Preempt(context.Context, *Request) (interface{}, error) {
	return nil, ErrNotHandled
}

func (defaultHandler) Handle(context.Context, *Request) (interface{}, error) {
	return nil, ErrNotHandled
}

type HandlerFunc func(ctx context.Context, req *Request) (interface{}, error)

func (f HandlerFunc) Handle(ctx context.Context, req *Request) (interface{}, error) {
	return f(ctx, req)
}

// async is a small helper for things with an asynchronous result that you can
// wait for.
type async struct {
	ready  chan struct{}
	errBox chan error
}

func (a *async) init() {
	a.ready = make(chan struct{})
	a.errBox = make(chan error, 1)
	a.errBox <- nil
}

func (a *async) done() {
	close(a.ready)
}

func (a *async) isDone() bool {
	select {
	case <-a.ready:
		return true
	default:
		return false
	}
}

func (a *async) wait() error {
	<-a.ready
	err := <-a.errBox
	a.errBox <- err
	return err
}

func (a *async) setError(err error) {
	storedErr := <-a.errBox
	if storedErr == nil {
		storedErr = err
	}
	a.errBox <- storedErr
}