Example #1
0
func (m *message) Decode(data []byte) error {
	m.Clear()
	if len(data) == 0 {
		return internal.Errorf("empty buffer for decode")
	}
	if C.pn_message_decode(m.pn, cPtr(data), cLen(data)) < 0 {
		return internal.Errorf("decoding message: %s",
			internal.PnError(unsafe.Pointer(C.pn_message_error(m.pn))))
	}
	return nil
}
Example #2
0
// Message decodes the message containined in a delivery.
// Will return an error if delivery.HasMessage() is false.
func (delivery Delivery) Message() (m amqp.Message, err error) {
	if !delivery.Readable() || delivery.Partial() {
		return nil, internal.Errorf("attempting to get incomplete message")
	}
	data := make([]byte, delivery.Pending())
	result := delivery.Link().Recv(data)
	if result != len(data) {
		return nil, internal.Errorf("cannot receive message: %s", internal.PnErrorCode(result))
	}
	m = amqp.NewMessage()
	err = m.Decode(data)
	return
}
Example #3
0
func dataError(prefix string, data *C.pn_data_t) error {
	err := internal.PnError(unsafe.Pointer(C.pn_data_error(data)))
	if err != nil {
		err = internal.Errorf("%s: %s", prefix, err.(internal.Error))
	}
	return err
}
Example #4
0
// ParseUrl parses an AMQP URL string and returns a net/url.Url.
//
// It is more forgiving than net/url.Parse and allows most of the parts of the
// URL to be missing, assuming AMQP defaults.
//
func ParseURL(s string) (u *url.URL, err error) {
	cstr := C.CString(s)
	defer C.free(unsafe.Pointer(cstr))
	pnUrl := C.pn_url_parse(cstr)
	if pnUrl == nil {
		return nil, internal.Errorf("bad URL %#v", s)
	}
	defer C.pn_url_free(pnUrl)

	scheme := C.GoString(C.pn_url_get_scheme(pnUrl))
	username := C.GoString(C.pn_url_get_username(pnUrl))
	password := C.GoString(C.pn_url_get_password(pnUrl))
	host := C.GoString(C.pn_url_get_host(pnUrl))
	port := C.GoString(C.pn_url_get_port(pnUrl))
	path := C.GoString(C.pn_url_get_path(pnUrl))

	if err != nil {
		return nil, internal.Errorf("bad URL %#v: %s", s, err)
	}
	if scheme == "" {
		scheme = amqp
	}
	if port == "" {
		if scheme == amqps {
			port = amqps
		} else {
			port = amqp
		}
	}
	var user *url.Userinfo
	if password != "" {
		user = url.UserPassword(username, password)
	} else if username != "" {
		user = url.User(username)
	}

	u = &url.URL{
		Scheme: scheme,
		User:   user,
		Host:   net.JoinHostPort(host, port),
		Path:   path,
	}

	return u, nil
}
Example #5
0
// decode from bytes.
// Return bytes decoded or 0 if we could not decode a complete object.
//
func decode(data *C.pn_data_t, bytes []byte) int {
	if len(bytes) == 0 {
		return 0
	}
	n := int(C.pn_data_decode(data, cPtr(bytes), cLen(bytes)))
	if n == int(C.PN_UNDERFLOW) {
		C.pn_error_clear(C.pn_data_error(data))
		return 0
	} else if n <= 0 {
		panic(internal.Errorf("unmarshal %s", internal.PnErrorCode(n)))
	}
	return n
}
Example #6
0
/*
Unmarshal decodes AMQP-encoded bytes and stores the result in the value pointed to by v.
Types are converted as follows:

 +---------------------------+----------------------------------------------------------------------+
 |To Go types                |From AMQP types                                                       |
 +===========================+======================================================================+
 |bool                       |bool                                                                  |
 +---------------------------+----------------------------------------------------------------------+
 |int, int8, int16,          |Equivalent or smaller signed integer type: byte, short, int, long.    |
 |int32, int64               |                                                                      |
 +---------------------------+----------------------------------------------------------------------+
 |uint, uint8, uint16,       |Equivalent or smaller unsigned integer type: ubyte, ushort, uint,     |
 |uint32, uint64 types       |ulong                                                                 |
 +---------------------------+----------------------------------------------------------------------+
 |float32, float64           |Equivalent or smaller float or double.                                |
 +---------------------------+----------------------------------------------------------------------+
 |string, []byte             |string, symbol or binary.                                             |
 +---------------------------+----------------------------------------------------------------------+
 |Symbol                     |symbol                                                                |
 +---------------------------+----------------------------------------------------------------------+
 |map[K]T                    |map, provided all keys and values can unmarshal to types K, T         |
 +---------------------------+----------------------------------------------------------------------+
 |Map                        |map, any AMQP map                                                     |
 +---------------------------+----------------------------------------------------------------------+
 |interface{}                |Any AMQP value can be unmarshaled to an interface{} as follows:       |
 |                           +------------------------+---------------------------------------------+
 |                           |AMQP Type               |Go Type in interface{}                       |
 |                           +========================+=============================================+
 |                           |bool                    |bool                                         |
 |                           +------------------------+---------------------------------------------+
 |                           |byte,short,int,long     |int8,int16,int32,int64                       |
 |                           +------------------------+---------------------------------------------+
 |                           |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                   |
 |                           +------------------------+---------------------------------------------+
 |                           |float, double           |float32, float64                             |
 |                           +------------------------+---------------------------------------------+
 |                           |string                  |string                                       |
 |                           +------------------------+---------------------------------------------+
 |                           |symbol                  |Symbol                                       |
 |                           +------------------------+---------------------------------------------+
 |                           |binary                  |Binary                                       |
 |                           +------------------------+---------------------------------------------+
 |                           |nulll                   |nil                                          |
 |                           +------------------------+---------------------------------------------+
 |                           |map                     |Map                                          |
 |                           +------------------------+---------------------------------------------+
 |                           |list                    |List                                         |
 +---------------------------+------------------------+---------------------------------------------+

The following Go types cannot be unmarshaled: uintptr, function, interface, channel.

TODO

Go types: array, struct.

AMQP types: decimal32/64/128, char (round trip), timestamp, uuid, array, multi-section message bodies.

AMQP maps with mixed/unhashable key types need an alternate representation.

Described types.
*/
func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
	defer doRecover(&err)

	data := C.pn_data(0)
	defer C.pn_data_free(data)
	n = decode(data, bytes)
	if n == 0 {
		err = internal.Errorf("not enough data")
	} else {
		unmarshal(v, data)
	}
	return
}
Example #7
0
// Send sends a amqp.Message over a Link.
// Returns a Delivery that can be use to determine the outcome of the message.
func (link Link) Send(m amqp.Message) (Delivery, error) {
	if !link.IsSender() {
		return Delivery{}, internal.Errorf("attempt to send message on receiving link")
	}
	delivery := link.Delivery(tags.Next())
	bytes, err := m.Encode(nil)
	if err != nil {
		return Delivery{}, internal.Errorf("cannot send mesage %s", err)
	}
	result := link.SendBytes(bytes)
	link.Advance()
	if result != len(bytes) {
		if result < 0 {
			return delivery, internal.Errorf("send failed %v", internal.PnErrorCode(result))
		} else {
			return delivery, internal.Errorf("send incomplete %v of %v", result, len(bytes))
		}
	}
	if link.RemoteSndSettleMode() == SndSettled {
		delivery.Settle()
	}
	return delivery, nil
}
Example #8
0
func (m *message) Encode(buffer []byte) ([]byte, error) {
	encode := func(buf []byte) ([]byte, error) {
		len := cLen(buf)
		result := C.pn_message_encode(m.pn, cPtr(buf), &len)
		switch {
		case result == C.PN_OVERFLOW:
			return buf, overflow
		case result < 0:
			return buf, internal.Errorf("cannot encode message: %s", internal.PnErrorCode(result))
		default:
			return buf[:len], nil
		}
	}
	return encodeGrow(buffer, encode)
}
Example #9
0
// HandleEvent handles an open/close event for an endpoint in a generic way.
func (d endpointDelegator) HandleEvent(e Event) {
	endpoint := d.endpoint(e)
	state := endpoint.State()

	switch e.Type() {

	case d.localOpen:
		if state.RemoteActive() {
			d.delegator.mhandler.HandleMessagingEvent(d.opened, e)
		}

	case d.remoteOpen:
		switch {
		case state.LocalActive():
			d.delegator.mhandler.HandleMessagingEvent(d.opened, e)
		case state.LocalUninit():
			d.delegator.mhandler.HandleMessagingEvent(d.opening, e)
			if d.delegator.AutoOpen {
				endpoint.Open()
			}
		}

	case d.remoteClose:
		if endpoint.RemoteCondition().IsSet() { // Closed with error
			d.delegator.mhandler.HandleMessagingEvent(d.error, e)
		} else {
			d.delegator.mhandler.HandleMessagingEvent(d.closing, e)
		}
		if state.LocalClosed() {
			d.delegator.mhandler.HandleMessagingEvent(d.closed, e)
		} else if state.LocalActive() {
			endpoint.Close()
		}

	case d.localClose:
		if state.RemoteClosed() {
			d.delegator.mhandler.HandleMessagingEvent(d.closed, e)
		}

	default:
		// We shouldn't be called with any other event type.
		panic(internal.Errorf("internal error, not an open/close event: %s", e))
	}
}
Example #10
0
// initLocal initializes a local link associated with a session.
// Call in proton goroutine
func makeLocalLink(sn *session, isSender bool, settings LinkSettings) (link, error) {
	var l link
	l.session = sn
	l.settings = settings
	l.isSender = isSender
	if l.settings.Name == "" {
		l.settings.Name = l.session.connection.container.nextLinkName()
	}
	if l.IsSender() {
		l.eLink = l.session.eSession.Sender(l.settings.Name)
	} else {
		l.eLink = l.session.eSession.Receiver(l.settings.Name)
	}
	if l.eLink.IsNil() {
		return l, l.setError(internal.Errorf("cannot create link %s", l))
	}
	l.setSettings()
	return l, nil
}
Example #11
0
// Called in proton goroutine
func (r *receiver) handleDelivery(delivery proton.Delivery) {
	// FIXME aconway 2015-09-24: how can this happen if we are remote closed?
	if r.eLink.State().RemoteClosed() {
		localClose(r.eLink, r.eLink.RemoteCondition().Error())
		return
	}
	if delivery.HasMessage() {
		m, err := delivery.Message()
		if err != nil {
			localClose(r.eLink, err)
			return
		}
		internal.Assert(m != nil)
		r.eLink.Advance()
		if r.eLink.Credit() < 0 {
			localClose(r.eLink, internal.Errorf("received message in excess of credit limit"))
		} else {
			// We never issue more credit than cap(buffer) so this will not block.
			r.buffer <- ReceivedMessage{m, delivery, r}
		}
	}
}
Example #12
0
func marshal(v interface{}, data *C.pn_data_t) {
	switch v := v.(type) {
	case nil:
		C.pn_data_put_null(data)
	case bool:
		C.pn_data_put_bool(data, C.bool(v))
	case int8:
		C.pn_data_put_byte(data, C.int8_t(v))
	case int16:
		C.pn_data_put_short(data, C.int16_t(v))
	case int32:
		C.pn_data_put_int(data, C.int32_t(v))
	case int64:
		C.pn_data_put_long(data, C.int64_t(v))
	case int:
		if unsafe.Sizeof(0) == 8 {
			C.pn_data_put_long(data, C.int64_t(v))
		} else {
			C.pn_data_put_int(data, C.int32_t(v))
		}
	case uint8:
		C.pn_data_put_ubyte(data, C.uint8_t(v))
	case uint16:
		C.pn_data_put_ushort(data, C.uint16_t(v))
	case uint32:
		C.pn_data_put_uint(data, C.uint32_t(v))
	case uint64:
		C.pn_data_put_ulong(data, C.uint64_t(v))
	case uint:
		if unsafe.Sizeof(0) == 8 {
			C.pn_data_put_ulong(data, C.uint64_t(v))
		} else {
			C.pn_data_put_uint(data, C.uint32_t(v))
		}
	case float32:
		C.pn_data_put_float(data, C.float(v))
	case float64:
		C.pn_data_put_double(data, C.double(v))
	case string:
		C.pn_data_put_string(data, pnBytes([]byte(v)))
	case []byte:
		C.pn_data_put_binary(data, pnBytes(v))
	case Binary:
		C.pn_data_put_binary(data, pnBytes([]byte(v)))
	case Symbol:
		C.pn_data_put_symbol(data, pnBytes([]byte(v)))
	case Map: // Special map type
		C.pn_data_put_map(data)
		C.pn_data_enter(data)
		for key, val := range v {
			marshal(key, data)
			marshal(val, data)
		}
		C.pn_data_exit(data)
	default:
		switch reflect.TypeOf(v).Kind() {
		case reflect.Map:
			putMap(data, v)
		case reflect.Slice:
			putList(data, v)
		default:
			panic(internal.Errorf("cannot marshal %s to AMQP", reflect.TypeOf(v)))
		}
	}
	err := dataError("marshal", data)
	if err != nil {
		panic(err)
	}
	return
}
Example #13
0
		switch {
		case n == int(C.PN_OVERFLOW):
			return buf, overflow
		case n < 0:
			return buf, dataError("marshal error", data)
		default:
			return buf[:n], nil
		}
	}
	return encodeGrow(buffer, encode)
}

const minEncode = 256

// overflow is returned when an encoding function can't fit data in the buffer.
var overflow = internal.Errorf("buffer too small")

// encodeFn encodes into buffer[0:len(buffer)].
// Returns buffer with length adjusted for data encoded.
// If buffer too small, returns overflow as error.
type encodeFn func(buffer []byte) ([]byte, error)

// encodeGrow calls encode() into buffer, if it returns overflow grows the buffer.
// Returns the final buffer.
func encodeGrow(buffer []byte, encode encodeFn) ([]byte, error) {
	if buffer == nil || len(buffer) == 0 {
		buffer = make([]byte, minEncode)
	}
	var err error
	for buffer, err = encode(buffer); err == overflow; buffer, err = encode(buffer) {
		buffer = make([]byte, 2*len(buffer))
Example #14
0
)

// Timeout is the error returned if an operation does not complete on time.
//
// Methods named *Timeout in this package take time.Duration timeout parameter.
//
// If timeout > 0 and there is no result available before the timeout, they
// return a zero or nil value and Timeout as an error.
//
// If timeout == 0 they will return a result if one is immediatley available or
// nil/zero and Timeout as an error if not.
//
// If timeout == Forever the function will return only when there is a result or
// some non-timeout error occurs.
//
var Timeout = internal.Errorf("timeout")

// Forever can be used as a timeout parameter to indicate wait forever.
const Forever time.Duration = -1

// timedReceive receives on channel (which can be a chan of any type), waiting
// up to timeout.
//
// timeout==0 means do a non-blocking receive attempt. timeout < 0 means block
// forever. Other values mean block up to the timeout.
//
func timedReceive(channel interface{}, timeout time.Duration) (value interface{}, ok bool, timedout bool) {
	cases := []reflect.SelectCase{
		reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(channel)},
	}
	switch {
Example #15
0
func (l *link) setPanicIfOpen() {
	if l.IsOpen() {
		panic(internal.Errorf("link is already open %s", l))
	}
}