func (c *Client) note(ctx context.Context, method string, params interface{}) (*jmessage, error) {
	bits, err := c.marshalParams(ctx, method, params)
	if err != nil {
		return nil, err
	}
	return &jmessage{M: method, P: bits}, nil
}
note constructs a notification request for the specified method and parameters.
package jrpc2
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strconv"
	"sync"
	"github.com/creachadair/jrpc2/channel"
	"github.com/creachadair/jrpc2/code"
)
type Client struct {
	done *sync.WaitGroup  
	log   func(string, ...interface{})  
	enctx encoder
	snote func(*jmessage)
	scall func(*jmessage) []byte
	chook func(*Client, *Response)
	allow1 bool  
	mu      sync.Mutex            
	ch      channel.Channel       
	err     error                 
	pending map[string]*Response  
	nextID  int64                 
}
func NewClient(ch channel.Channel, opts *ClientOptions) *Client {
	c := &Client{
		done:   new(sync.WaitGroup),
		log:    opts.logFunc(),
		allow1: opts.allowV1(),
		enctx:  opts.encodeContext(),
		snote:  opts.handleNotification(),
		scall:  opts.handleCallback(),
		chook:  opts.handleCancel(),
		ch:      ch,
		pending: make(map[string]*Response),
		nextID:  1,
	}
	c.done.Add(1)
	go func() {
		defer c.done.Done()
		for c.accept(ch) == nil {
		}
	}()
	return c
}
func (c *Client) accept(ch receiver) error {
	var in jmessages
	bits, err := ch.Recv()
	if err == nil {
		err = in.parseJSON(bits)
	}
	if err != nil {
		if !isUninteresting(err) {
			c.log("Decoding error: %v", err)
		}
		c.mu.Lock()
		c.stop(err)
		c.mu.Unlock()
		return err
	}
	c.log("Received %d responses", len(in))
	c.done.Add(1)
	go func() {
		defer c.done.Done()
		c.mu.Lock()
		defer c.mu.Unlock()
		for _, rsp := range in {
			c.deliver(rsp)
		}
	}()
	return nil
}
func (c *Client) handleRequest(msg *jmessage) {
	if msg.isNotification() {
		if c.snote == nil {
			c.log("Discarding notification: %v", msg)
		} else {
			c.snote(msg)
		}
	} else if c.scall == nil {
		c.log("Discarding callback request: %v", msg)
	} else if c.ch == nil {
		c.log("Client channel is closed; discarding callback: %v", msg)
	} else {
		bits := c.scall(msg)
		if err := c.ch.Send(bits); err != nil {
			c.log("Sending reply for callback %v failed: %v", msg, err)
		}
	}
}
func (c *Client) deliver(rsp *jmessage) {
	if rsp.isRequestOrNotification() {
		c.handleRequest(rsp)
		return
	}
	id := string(fixID(rsp.ID))
	if p := c.pending[id]; p == nil {
		c.log("Discarding response for unknown ID %q", id)
	} else if !c.versionOK(rsp.V) {
		delete(c.pending, id)
		p.ch <- &jmessage{
			ID: rsp.ID,
			E: &Error{
				Code:    code.InvalidRequest,
				Message: fmt.Sprintf("incorrect version marker %q", rsp.V),
			},
		}
		c.log("Invalid response for ID %q", id)
	} else {
		delete(c.pending, id)
		p.ch <- rsp
		c.log("Completed request for ID %q", id)
	}
}
func (c *Client) req(ctx context.Context, method string, params interface{}) (*jmessage, error) {
	bits, err := c.marshalParams(ctx, method, params)
	if err != nil {
		return nil, err
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	id := json.RawMessage(strconv.FormatInt(c.nextID, 10))
	c.nextID++
	return &jmessage{
		ID: id,
		M:  method,
		P:  bits,
	}, nil
}