agent/wsclient/decode.go
func DecodeConnectionError(data []byte, dec TypeDecoder) (interface{}, string, error) {
	var acsErr map[string]string
	err := json.Unmarshal(data, &acsErr)
	if err != nil {
		return nil, "", &UndecodableMessage{string(data)}
	}
	if len(acsErr) != 1 {
		return nil, "", &UndecodableMessage{string(data)}
	}
	var typeStr string
	for key := range acsErr {
		typeStr = key
	}
	errType, ok := dec.NewOfType(typeStr)
	if !ok {
		return nil, typeStr, &UnrecognizedWSRequestType{}
	}

	val := reflect.ValueOf(errType)
	if val.Kind() != reflect.Ptr {
		return nil, typeStr, &UnrecognizedWSRequestType{"Non-pointer kind: " + val.Kind().String()}
	}
	ret := reflect.New(val.Elem().Type())
	retObj := ret.Elem()

	if retObj.Kind() != reflect.Struct {
		return nil, typeStr, &UnrecognizedWSRequestType{"Pointer to non-struct kind: " + retObj.Kind().String()}
	}

	msgField := retObj.FieldByName("Message_")
	if !msgField.IsValid() {
		return nil, typeStr, &UnrecognizedWSRequestType{"Expected error type to have 'Message' field"}
	}
	if msgField.IsValid() && msgField.CanSet() {
		msgStr := acsErr[typeStr]
		msgStrVal := reflect.ValueOf(&msgStr)
		if !msgStrVal.Type().AssignableTo(msgField.Type()) {
			return nil, typeStr, &UnrecognizedWSRequestType{"Type mismatch; 'Message' field must be a *string"}
		}
		msgField.Set(msgStrVal)
		return ret.Interface(), typeStr, nil
	}
	return nil, typeStr, &UnrecognizedWSRequestType{"Invalid message field; must not be nil"}
}
func DecodeConnectionError(data []byte, dec TypeDecoder) (interface{}, string, error) {
	var acsErr map[string]string
	err := json.Unmarshal(data, &acsErr)
	if err != nil {
		return nil, "", &UndecodableMessage{string(data)}
	}
	if len(acsErr) != 1 {
		return nil, "", &UndecodableMessage{string(data)}
	}
	var typeStr string
	for key := range acsErr {
		typeStr = key
	}
	errType, ok := dec.NewOfType(typeStr)
	if !ok {
		return nil, typeStr, &UnrecognizedWSRequestType{}
	}

	val := reflect.ValueOf(errType)
	if val.Kind() != reflect.Ptr {
		return nil, typeStr, &UnrecognizedWSRequestType{"Non-pointer kind: " + val.Kind().String()}
	}
	ret := reflect.New(val.Elem().Type())
	retObj := ret.Elem()

	if retObj.Kind() != reflect.Struct {
		return nil, typeStr, &UnrecognizedWSRequestType{"Pointer to non-struct kind: " + retObj.Kind().String()}
	}

	msgField := retObj.FieldByName("Message_")
	if !msgField.IsValid() {
		return nil, typeStr, &UnrecognizedWSRequestType{"Expected error type to have 'Message' field"}
	}
	if msgField.IsValid() && msgField.CanSet() {
		msgStr := acsErr[typeStr]
		msgStrVal := reflect.ValueOf(&msgStr)
		if !msgStrVal.Type().AssignableTo(msgField.Type()) {
			return nil, typeStr, &UnrecognizedWSRequestType{"Type mismatch; 'Message' field must be a *string"}
		}
		msgField.Set(msgStrVal)
		return ret.Interface(), typeStr, nil
	}
	return nil, typeStr, &UnrecognizedWSRequestType{"Invalid message field; must not be nil"}
}
// DecodeConnectionError decodes some of the connection errors returned by the
// backend. Some differ from the usual ones in that they do not have a 'type'
// and 'message' field, but rather are of the form {"ErrorType":"ErrorMessage"}