whatcanGOwrong
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// This file contains utilities for decoding JSON-encoded bytes into DAP message.
|
||||
|
||||
package dap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DecodeProtocolMessageFieldError describes which JSON attribute
|
||||
// has an unsupported value that the decoding cannot handle.
|
||||
type DecodeProtocolMessageFieldError struct {
|
||||
Seq int
|
||||
SubType string
|
||||
FieldName string
|
||||
FieldValue string
|
||||
Message json.RawMessage
|
||||
}
|
||||
|
||||
func (e *DecodeProtocolMessageFieldError) Error() string {
|
||||
return fmt.Sprintf("%s %s '%s' is not supported (seq: %d)", e.SubType, e.FieldName, e.FieldValue, e.Seq)
|
||||
}
|
||||
|
||||
// defaultCodec is used to decode vanilla DAP messages.
|
||||
var defaultCodec = NewCodec()
|
||||
|
||||
// Codec is responsible for turning byte blobs into DAP messages.
|
||||
type Codec struct {
|
||||
eventCtor map[string]messageCtor
|
||||
requestCtor map[string]messageCtor
|
||||
responseCtor map[string]messageCtor
|
||||
}
|
||||
|
||||
// NewCodec constructs a new codec that extends the vanilla DAP protocol.
|
||||
// Unless you need to register custom DAP messages, use
|
||||
// DecodeProtocolMessage instead.
|
||||
func NewCodec() *Codec {
|
||||
ret := &Codec{
|
||||
eventCtor: make(map[string]messageCtor),
|
||||
requestCtor: make(map[string]messageCtor),
|
||||
responseCtor: make(map[string]messageCtor),
|
||||
}
|
||||
for k, v := range eventCtor {
|
||||
ret.eventCtor[k] = v
|
||||
}
|
||||
for k, v := range requestCtor {
|
||||
ret.requestCtor[k] = v
|
||||
}
|
||||
for k, v := range responseCtor {
|
||||
ret.responseCtor[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// RegisterRequest registers a new custom DAP command, so that it can be
|
||||
// unmarshalled by DecodeMessage. Returns an error when the command already
|
||||
// exists.
|
||||
//
|
||||
// The ctor functions need to return a new instance of the underlying DAP
|
||||
// message type. A typical usage looks like this:
|
||||
//
|
||||
// reqCtor := func() Message { return &LaunchRequest{} }
|
||||
// respCtor := func() Message { return &LaunchResponse{} }
|
||||
// codec.RegisterRequest("launch", reqCtor, respCtor)
|
||||
func (c *Codec) RegisterRequest(command string, requestCtor, responseCtor func() Message) error {
|
||||
_, hasReqCtor := c.requestCtor[command]
|
||||
_, hasRespCtor := c.responseCtor[command]
|
||||
if hasReqCtor || hasRespCtor {
|
||||
return fmt.Errorf("command %q is already registered", command)
|
||||
}
|
||||
c.requestCtor[command] = requestCtor
|
||||
c.responseCtor[command] = responseCtor
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterEvent registers a new custom DAP event, so that it can be
|
||||
// unmarshalled by DecodeMessage. Returns an error when the event already
|
||||
// exists.
|
||||
//
|
||||
// The ctor function needs to return a new instance of the underlying DAP
|
||||
// message type. A typical usage looks like this:
|
||||
//
|
||||
// ctor := func() Message { return &StoppedEvent{} }
|
||||
// codec.RegisterEvent("stopped", ctor)
|
||||
func (c *Codec) RegisterEvent(event string, ctor func() Message) error {
|
||||
if _, hasEventCtor := c.eventCtor[event]; hasEventCtor {
|
||||
return fmt.Errorf("event %q is already registered", event)
|
||||
}
|
||||
c.eventCtor[event] = ctor
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMessage parses the JSON-encoded data and returns the result of
|
||||
// the appropriate type within the ProtocolMessage hierarchy. If message type,
|
||||
// command, etc cannot be cast, returns DecodeProtocolMessageFieldError.
|
||||
// See also godoc for json.Unmarshal, which is used for underlying decoding.
|
||||
func (c *Codec) DecodeMessage(data []byte) (Message, error) {
|
||||
// This struct is the union of the ResponseMessage, RequestMessage, and
|
||||
// EventMessage types. It is an optimization that saves an additional
|
||||
// json.Unmarshal call.
|
||||
var m struct {
|
||||
ProtocolMessage
|
||||
Command string `json:"command"`
|
||||
Event string `json:"event"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch m.Type {
|
||||
case "request":
|
||||
return c.decodeRequest(m.Command, m.Seq, data)
|
||||
case "response":
|
||||
return c.decodeResponse(m.Command, m.Seq, m.Success, data)
|
||||
case "event":
|
||||
return c.decodeEvent(m.Event, m.Seq, data)
|
||||
default:
|
||||
return nil, &DecodeProtocolMessageFieldError{m.Seq, "ProtocolMessage", "type", m.Type, json.RawMessage(data)}
|
||||
}
|
||||
}
|
||||
|
||||
// decodeRequest determines what request type in the ProtocolMessage hierarchy
|
||||
// data corresponds to and uses json.Unmarshal to populate the corresponding
|
||||
// struct to be returned.
|
||||
func (c *Codec) decodeRequest(command string, seq int, data []byte) (Message, error) {
|
||||
ctor, ok := c.requestCtor[command]
|
||||
if !ok {
|
||||
return nil, &DecodeProtocolMessageFieldError{seq, "Request", "command", command, json.RawMessage(data)}
|
||||
}
|
||||
requestPtr := ctor()
|
||||
err := json.Unmarshal(data, requestPtr)
|
||||
return requestPtr, err
|
||||
}
|
||||
|
||||
// decodeResponse determines what response type in the ProtocolMessage hierarchy
|
||||
// data corresponds to and uses json.Unmarshal to populate the corresponding
|
||||
// struct to be returned.
|
||||
func (c *Codec) decodeResponse(command string, seq int, success bool, data []byte) (Message, error) {
|
||||
if !success {
|
||||
var er ErrorResponse
|
||||
err := json.Unmarshal(data, &er)
|
||||
return &er, err
|
||||
}
|
||||
ctor, ok := c.responseCtor[command]
|
||||
if !ok {
|
||||
return nil, &DecodeProtocolMessageFieldError{seq, "Response", "command", command, json.RawMessage(data)}
|
||||
}
|
||||
responsePtr := ctor()
|
||||
err := json.Unmarshal(data, responsePtr)
|
||||
return responsePtr, err
|
||||
}
|
||||
|
||||
// decodeEvent determines what event type in the ProtocolMessage hierarchy
|
||||
// data corresponds to and uses json.Unmarshal to populate the corresponding
|
||||
// struct to be returned.
|
||||
func (c *Codec) decodeEvent(event string, seq int, data []byte) (Message, error) {
|
||||
ctor, ok := c.eventCtor[event]
|
||||
if !ok {
|
||||
return nil, &DecodeProtocolMessageFieldError{seq, "Event", "event", event, json.RawMessage(data)}
|
||||
}
|
||||
eventPtr := ctor()
|
||||
err := json.Unmarshal(data, eventPtr)
|
||||
return eventPtr, err
|
||||
}
|
||||
|
||||
// DecodeProtocolMessage parses the JSON-encoded ProtocolMessage and returns
|
||||
// the message embedded in it. If message type, command, etc cannot be cast,
|
||||
// returns DecodeProtocolMessageFieldError. See also godoc for json.Unmarshal,
|
||||
// which is used for underlying decoding.
|
||||
func DecodeProtocolMessage(data []byte) (Message, error) {
|
||||
return defaultCodec.DecodeMessage(data)
|
||||
}
|
||||
|
||||
type messageCtor func() Message
|
||||
Reference in New Issue
Block a user