Platforms to show: All Mac Windows Linux Cross-Platform
/RabbitMQ/RabbitMQTutorial/RabbitMQTutorial
Required plugins for this example: MBS RabbitMQ Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /RabbitMQ/RabbitMQTutorial/RabbitMQTutorial
This example is the version from Sun, 15th May 2021.
Project "RabbitMQTutorial.xojo_binary_project"
Class App Inherits ConsoleApplication
Const constBindingKey = "hello"
Const constChannel = 1
Const constExchange = "amq.direct"
Const constHostname = "localhost"
Const constLoginPassword = "guest"
Const constLoginUsername = "guest"
Const constPort = 5672
Const constQueue_HelloWorld = "hello"
Const constQueue_RPC = "rpc_queue"
EventHandler Function Run(args() as String) As Integer
AppRandom = New Random
Dim iChoice As Integer = Val(me.TutorialChoice())
select case iChoice
case 1
me.Tutorial_1_Receive()
case 2
me.Tutorial_2_Send()
case 3
me.Tutorial_3_RPC_Server()
case 4
me.Tutorial_4_RPC_Client()
end select
DoEvents(100)
call me.WaitKeyInput("Press <enter> to exit.")
Quit(0)
End EventHandler
Function Failed(r as RabbitMQRPCReplyMBS) As Boolean
If r = Nil Then
Return True
End If
Select Case r.Type
Case r.ResponseTypeNone
Break
Case r.ResponseTypeNormal
Return False // okay
Case r.ResponseTypeLibraryException
me.Output("Library error: "+Str(r.LibraryError)+" "+RabbitMQConnectionMBS.ErrorString(r.LibraryError))
Return True
Case r.ResponseTypeServerException
Dim d As Dictionary = r.MethodDecoded
Dim c As String = d.Lookup("ReplyCode", "")
Dim t As String = d.Lookup("ReplyText", "")
me.Output("Server error "+c+": "+t)
If t = "" Then Break
Return True
end Select
End Function
Private Function Fib(n As Integer) As Integer
If n < 2 Then Return n
Return Fib(n - 1) + Fib(n - 2)
End Function
Private Function GetGUID() As String
//HACKY... don't use for production
eiGuidNr = eiGuidNr + 1
return Format(eiGuidNr, "00000000") + "-" + _
Format(eiGuidNr, "0000") + "-" + _
Format(eiGuidNr, "0000") + "-" + _
Format(eiGuidNr, "0000") + "-" + _
Format(eiGuidNr, "000000000000") + "-"
End Function
Private Sub Output(psText As String)
StdOut.WriteLine(ReplaceLineEndings(psText, " "))
stdout.Flush()
End Sub
Private Function TutorialChoice() As String
Dim conn As New RabbitMQConnectionMBS
me.Output("MBS Xojo RabbitMQ Plugin")
me.Output("************************")
me.Output("RabbitMQConnectionMBS.Version: " + conn.Version)
me.Output("")
me.Output("RabbitMQ Tutorials")
me.Output("------------------")
me.Output("https://www.rabbitmq.com/getstarted.html")
me.Output("")
me.Output("1 - Hello World - Receive")
me.Output("2 - Hello World - Send")
me.Output("3 - RPC - Server")
me.Output("4 - RPC - Client")
me.Output("")
return me.WaitKeyInput("Choice: ")
End Function
Private Sub Tutorial_1_Receive()
Dim conn As New RabbitMQConnectionMBS
If Not conn.NewTCPSocket Then
me.Output("RabbitMQConnectionMBS: Failed to create TCP socket")
Return
End If
Dim status As Integer = conn.OpenSocket(constHostname, constPort)
If status <> 0 Then
me.Output("RabbitMQConnectionMBS: Failed to open TCP socket")
Return
End If
me.Output("- conn.LoginPlain")
Dim r As RabbitMQRPCReplyMBS = conn.LoginPlain("/", 0, 131072, 0, constLoginUsername, constLoginPassword)
If Failed(r) Then Return
me.Output("- conn.ChannelOpen")
Call conn.ChannelOpen(constChannel)
r = conn.RPCReply
If Failed(r) Then Return
Const passive = False
Const durable = False
Const exclusive = False
Const autoDelete = False
Dim arguments As Dictionary = Nil
Dim frame as RabbitMQFrameMBS
me.Output("- conn.QueueDeclare")
Dim QueueDeclareResult As Dictionary = conn.QueueDeclare(constChannel, constQueue_HelloWorld, passive, durable, exclusive, autoDelete, arguments)
r = conn.RPCReply
If Failed(r) Then Return
Dim queuename As String = QueueDeclareResult.Value("queue")
If queuename.Len = 0 Then Break // failed?
me.Output(" -> Queuename: "+queuename)
Const consumerTag = ""
Const noLocal = False
Const noAck = true
me.Output("- conn.QueueBind")
Dim QueueBindResult As Dictionary = conn.QueueBind(constChannel, queuename, constExchange, constBindingKey, arguments)
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- conn.BasicConsume")
Dim BasicConsumeResult As Dictionary = conn.BasicConsume(constChannel, queuename, consumerTag, noLocal, noAck, exclusive, arguments)
'* Synchonously polls the broker for a message in a queue, and
'* retrieves the message if a message is in the queue.
'*
'* \param [in] state the connection object
'* \param [in] channel the channel identifier to use
'* \param [in] queue the queue name to retrieve from
'* \param [in] no_ack if true the message is automatically ack'ed
'* if false amqp_basic_ack should be called once the message
'* retrieved has been processed
'* \return amqp_rpc_reply indicating success or failure
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- listening...")
While True
Dim res As RabbitMQRPCReplyMBS
dim envelope as RabbitMQEnvelopeMBS
res = conn.ConsumeMessage(envelope, 0.01)
If res.Type = res.ResponseTypeNormal Then
// got data
me.Output("")
me.Output("- conn.ConsumeMessage -> got data")
me.Output("Envelope.DeliveryTag: "+Str(envelope.DeliveryTag))
me.Output("Envelope.Exchange: "+envelope.Exchange)
me.Output("Envelope.Routingkey: "+envelope.Routingkey)
Dim properties As RabbitMQBasicPropertiesMBS = envelope.message.properties
'Dim Flags As Integer = properties.flags
'If BitwiseAnd(Flags, RabbitMQBasicPropertiesMBS.kFlagContentType) = RabbitMQBasicPropertiesMBS.kFlagContentType Then
me.Output("Envelope.Message.Properties.AppId: " + properties.AppId)
me.Output("Envelope.Message.Properties.ContentType: " + properties.ContentType)
me.Output("Envelope.Message.Properties.ContentEncoding: " + properties.ContentEncoding)
me.Output("Envelope.Message.Properties.Expiration: " + properties.Expiration)
Dim BodyString As String = envelope.Message.Body
me.Output("Envelope.Message.Body: " + BodyString)
else
If res.ResponseTypeLibraryException = res.Type And conn.kStatusUnexpectedState = res.LibraryError Then
Dim ir As Integer = conn.SimpleWaitFrame(frame)
If conn.kStatusOk <> ir Then
me.Output("conn.kStatusOk <> ir")
Return
End If
If frame.kFrameMethod = frame.FrameType Then
Select Case frame.MethodID
Case frame.kBasicAckMethod
//* If we've turned publisher confirms on, and we've published a
//* message here Is a message being confirmed.
//*/
Case frame.kBasicReturnMethod
//* If a published message couldn't be routed and the mandatory
//* flag was set this Is what would be returned. The message Then
//* needs To be read.
//*/
Dim message As RabbitMQMessageMBS
res = conn.ReadMessage(frame.channel, message)
If res.ResponseTypeNormal <> res.type Then
Return
End If
Case frame.kChannelCloseMethod
//* a channel.close method happens when a channel Exception occurs,
//* this can happen by publishing To an exchange that doesn't exist
//* For example.
//*
//* In this Case you would need To open another channel redeclare
//* any queues that were declared Auto-delete, And restart any
//* consumers that were attached To the previous channel.
//*/
return
Case frame.kConnectionCloseMethod
//* a connection.close method happens when a connection Exception
//* occurs, this can happen by trying To use a channel that isn't
//* open For example.
//*
//* In this Case the whole connection must be restarted.
//*/
return
Else
me.Output "An unexpected method was received: "+str(frame.MethodID)
Return
end Select
End If
End If
end if
app.DoEvents(100)
wend
me.Output("- conn.ConnectionClose")
r = conn.ConnectionClose
If Failed(r) Then Return
End Sub
Private Sub Tutorial_2_Send()
Const messagebody = "Hello RabbitMQ World from Xojo"
Const routingkey = "hello"
Dim conn As New RabbitMQConnectionMBS
If Not conn.NewTCPSocket Then
me.Output("RabbitMQConnectionMBS: Failed to create TCP socket")
Return
End If
Dim status As Integer = conn.OpenSocket(constHostname, constPort)
If status <> 0 Then
me.Output("RabbitMQConnectionMBS: Failed to open TCP socket")
Return
End If
me.Output("- conn.LoginPlain")
Dim r As RabbitMQRPCReplyMBS = conn.LoginPlain("/", 0, 131072, 0, constLoginUsername, constLoginPassword)
If Failed(r) Then Return
me.Output("- conn.ChannelOpen")
Call conn.ChannelOpen(constChannel)
r = conn.RPCReply
If Failed(r) Then Return
Dim props As New RabbitMQBasicPropertiesMBS
props.Flags = props.kFlagContentType Or props.kFlagDeliveryMode or props.kFlagContentEncoding
props.ContentType = "text/plain"
props.ContentEncoding = "UTF8"
props.DeliveryMode = props.kDeliveryPersistent
Dim ErrorCode As Integer = conn.BasicPublish(constChannel, constExchange, routingkey, False, False, props, messagebody)
If ErrorCode <> 0 Then
me.Output("- conn.BasicPublish: Failed to publish.")
Return
Else
me.Output("- conn.BasicPublish: sent")
End If
me.Output("- conn.ChannelClose")
r = conn.ChannelClose(constChannel, RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
me.Output("- conn.ConnectionClose")
r = conn.ConnectionClose(RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
End Sub
Private Sub Tutorial_3_RPC_Server()
Dim conn As New RabbitMQConnectionMBS
If Not conn.NewTCPSocket Then
me.Output("RabbitMQConnectionMBS: Failed to create TCP socket")
Return
End If
Dim status As Integer = conn.OpenSocket(constHostname, constPort)
If status <> 0 Then
me.Output("RabbitMQConnectionMBS: Failed to open TCP socket")
Return
End If
me.Output("- conn.LoginPlain")
Dim r As RabbitMQRPCReplyMBS = conn.LoginPlain("/", 0, 131072, 0, constLoginUsername, constLoginPassword)
If Failed(r) Then Return
me.Output("- conn.ChannelOpen")
Call conn.ChannelOpen(constChannel)
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- conn.BasicQOS")
call conn.BasicQOS(constChannel, 0, 1, false) //param4 -> global
Const passive = False
Const durable = False
Const exclusive = False
Const autoDelete = False
Dim arguments As Dictionary = Nil
Dim frame as RabbitMQFrameMBS
me.Output("- conn.QueueDeclare")
Dim QueueDeclareResult As Dictionary = conn.QueueDeclare(constChannel, constQueue_RPC, passive, durable, exclusive, autoDelete, arguments)
r = conn.RPCReply
If Failed(r) Then Return
Dim queuename As String = QueueDeclareResult.Value("queue")
If queuename.Len = 0 Then Break // failed?
me.Output(" -> Queuename: "+queuename)
Const consumerTag = ""
Const noLocal = False
Const noAck = False
me.Output("- conn.QueueBind")
Dim QueueBindResult As Dictionary = conn.QueueBind(constChannel, queuename, constExchange, constBindingKey, arguments)
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- conn.BasicConsume")
Dim BasicConsumeResult As Dictionary = conn.BasicConsume(constChannel, queuename, consumerTag, noLocal, noAck, exclusive, arguments)
'* Synchonously polls the broker for a message in a queue, and
'* retrieves the message if a message is in the queue.
'*
'* \param [in] state the connection object
'* \param [in] channel the channel identifier to use
'* \param [in] queue the queue name to retrieve from
'* \param [in] no_ack if true the message is automatically ack'ed
'* if false amqp_basic_ack should be called once the message
'* retrieved has been processed
'* \return amqp_rpc_reply indicating success or failure
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- Awaiting RPC requests...")
While True
Dim res As RabbitMQRPCReplyMBS
dim envelope as RabbitMQEnvelopeMBS
res = conn.ConsumeMessage(envelope, 0.01)
If res.Type = res.ResponseTypeNormal Then
// got data
'Read Request
'************
me.Output("")
me.Output("- conn.ConsumeMessage -> got data")
Dim iDeliveryTag As UInt64 = envelope.DeliveryTag
me.Output("Envelope.DeliveryTag: "+Str(envelope.DeliveryTag))
me.Output("Envelope.Exchange: "+envelope.Exchange)
me.Output("Envelope.Routingkey: "+envelope.Routingkey)
Dim properties As RabbitMQBasicPropertiesMBS = envelope.message.properties
'Dim Flags As Integer = properties.flags
'If BitwiseAnd(Flags, RabbitMQBasicPropertiesMBS.kFlagContentType) = RabbitMQBasicPropertiesMBS.kFlagContentType Then
me.Output("Envelope.Message.Properties.AppId: " + properties.AppId)
me.Output("Envelope.Message.Properties.ContentType: " + properties.ContentType)
me.Output("Envelope.Message.Properties.ContentEncoding: " + properties.ContentEncoding)
me.Output("Envelope.Message.Properties.Expiration: " + properties.Expiration)
Dim sCorrelationId As String = properties.CorrelationId
me.Output("Envelope.Message.Properties.CorrelationId: " + properties.CorrelationId)
Dim sReplyTo As String = properties.ReplyTo
me.Output("Envelope.Message.Properties.ReplyTo: " + properties.ReplyTo)
Dim BodyString As String = envelope.Message.Body
me.Output("Envelope.Message.Body: " + BodyString)
'Process Request
'***************
me.Output("")
me.Output("- FIB(" + BodyString + ")")
Dim fib As Integer = me.Fib(Val(BodyString))
me.Output(" -> " + Str(fib))
'Send Confirmation Reply
'***********************
Dim replyProps As New RabbitMQBasicPropertiesMBS
replyProps.Flags = replyProps.kFlagContentType Or replyProps.kFlagDeliveryMode or replyProps.kFlagContentEncoding or replyProps.kFlagCorrelationId
replyProps.ContentType = "text/plain"
replyProps.ContentEncoding = "UTF8"
replyProps.DeliveryMode = replyProps.kDeliveryPersistent
replyProps.CorrelationId = sCorrelationId
Dim sMessagebody As String = Str(fib)
Dim ErrorCode As Integer = conn.BasicPublish(constChannel, "", sReplyTo, False, False, replyProps, sMessagebody)
If ErrorCode <> 0 Then
me.Output("- conn.BasicPublish: Failed to publish.")
Return
Else
me.Output("- conn.BasicPublish: sent")
End If
me.Output("- conn.BasicAck: " + Str(iDeliveryTag))
call conn.BasicAck(constChannel, iDeliveryTag, false)
else
If res.ResponseTypeLibraryException = res.Type And conn.kStatusUnexpectedState = res.LibraryError Then
Dim ir As Integer = conn.SimpleWaitFrame(frame)
If conn.kStatusOk <> ir Then
me.Output("conn.kStatusOk <> ir")
Return
End If
If frame.kFrameMethod = frame.FrameType Then
Select Case frame.MethodID
Case frame.kBasicAckMethod
//* If we've turned publisher confirms on, and we've published a
//* message here Is a message being confirmed.
//*/
Case frame.kBasicReturnMethod
//* If a published message couldn't be routed and the mandatory
//* flag was set this Is what would be returned. The message Then
//* needs To be read.
//*/
Dim message As RabbitMQMessageMBS
res = conn.ReadMessage(frame.channel, message)
If res.ResponseTypeNormal <> res.type Then
Return
End If
Case frame.kChannelCloseMethod
//* a channel.close method happens when a channel Exception occurs,
//* this can happen by publishing To an exchange that doesn't exist
//* For example.
//*
//* In this Case you would need To open another channel redeclare
//* any queues that were declared Auto-delete, And restart any
//* consumers that were attached To the previous channel.
//*/
return
Case frame.kConnectionCloseMethod
//* a connection.close method happens when a connection Exception
//* occurs, this can happen by trying To use a channel that isn't
//* open For example.
//*
//* In this Case the whole connection must be restarted.
//*/
return
Else
me.Output "An unexpected method was received: "+str(frame.MethodID)
Return
end Select
End If
End If
end if
app.DoEvents(100)
wend
me.Output("- conn.ChannelClose")
r = conn.ChannelClose(constChannel, RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
me.Output("- conn.ConnectionClose")
r = conn.ConnectionClose(RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
End Sub
Private Sub Tutorial_4_RPC_Client()
Dim iRandom As Integer = AppRandom.InRange(10, 32)
Dim sGuid As String = me.GetGUID()
Dim conn As New RabbitMQConnectionMBS
If Not conn.NewTCPSocket Then
me.Output("RabbitMQConnectionMBS: Failed to create TCP socket")
Return
End If
Dim status As Integer = conn.OpenSocket(constHostname, constPort)
If status <> 0 Then
me.Output("RabbitMQConnectionMBS: Failed to open TCP socket")
Return
End If
me.Output("- conn.LoginPlain")
Dim r As RabbitMQRPCReplyMBS = conn.LoginPlain("/", 0, 131072, 0, constLoginUsername, constLoginPassword)
If Failed(r) Then Return
me.Output("- conn.ChannelOpen")
Call conn.ChannelOpen(constChannel)
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- conn.QueueDeclare")
Dim QueueDeclareResult As Dictionary = conn.QueueDeclare(constChannel, "", false, false, true, true, nil)
r = conn.RPCReply
If Failed(r) Then Return
Dim sReplyQueueName As String = QueueDeclareResult.Value("queue")
If sReplyQueueName.Len = 0 Then Break // failed?
me.Output(" -> Queuename: "+ sReplyQueueName)
Dim props As New RabbitMQBasicPropertiesMBS
props.Flags = props.kFlagContentType Or props.kFlagDeliveryMode or props.kFlagContentEncoding or props.kFlagCorrelationId or props.kFlagReplyTo
props.ContentType = "text/plain"
props.ContentEncoding = "UTF8"
props.DeliveryMode = props.kDeliveryPersistent
props.CorrelationId = sGuid
props.ReplyTo = sReplyQueueName
me.Output("- props.CorrelationId: " + props.CorrelationId)
me.Output("- MessageBody: " + Str(iRandom))
Dim messagebody As String = Str(iRandom)
Dim ErrorCode As Integer = conn.BasicPublish(constChannel, "", constQueue_RPC, False, false, props, messagebody)
If ErrorCode <> 0 Then
me.Output("- conn.BasicPublish: Failed to publish.")
Return
Else
me.Output("- conn.BasicPublish: sent")
End If
Const consumerTag = ""
Const noLocal = False
Const noAck = true
const exclusive = false
me.Output("- conn.BasicConsume")
Dim BasicConsumeResult As Dictionary = conn.BasicConsume(constChannel, sReplyQueueName, consumerTag, noLocal, noAck, exclusive, nil)
'* Synchonously polls the broker for a message in a queue, and
'* retrieves the message if a message is in the queue.
'*
'* \param [in] state the connection object
'* \param [in] channel the channel identifier to use
'* \param [in] queue the queue name to retrieve from
'* \param [in] no_ack if true the message is automatically ack'ed
'* if false amqp_basic_ack should be called once the message
'* retrieved has been processed
'* \return amqp_rpc_reply indicating success or failure
r = conn.RPCReply
If Failed(r) Then Return
me.Output("- listening...")
Dim frame as RabbitMQFrameMBS
While True
Dim res As RabbitMQRPCReplyMBS
dim envelope as RabbitMQEnvelopeMBS
res = conn.ConsumeMessage(envelope, 0.01)
If res.Type = res.ResponseTypeNormal Then
// got data
me.Output("")
me.Output("- conn.ConsumeMessage -> got data")
me.Output("Envelope.DeliveryTag: "+Str(envelope.DeliveryTag))
me.Output("Envelope.Exchange: "+envelope.Exchange)
me.Output("Envelope.Routingkey: "+envelope.Routingkey)
Dim properties As RabbitMQBasicPropertiesMBS = envelope.message.properties
'Dim Flags As Integer = properties.flags
'If BitwiseAnd(Flags, RabbitMQBasicPropertiesMBS.kFlagContentType) = RabbitMQBasicPropertiesMBS.kFlagContentType Then
me.Output("Envelope.Message.Properties.AppId: " + properties.AppId)
me.Output("Envelope.Message.Properties.ContentType: " + properties.ContentType)
me.Output("Envelope.Message.Properties.ContentEncoding: " + properties.ContentEncoding)
me.Output("Envelope.Message.Properties.Expiration: " + properties.Expiration)
Dim BodyString As String = envelope.Message.Body
me.Output("Envelope.Message.Body: " + BodyString)
exit 'Loop
else
If res.ResponseTypeLibraryException = res.Type And conn.kStatusUnexpectedState = res.LibraryError Then
Dim ir As Integer = conn.SimpleWaitFrame(frame)
If conn.kStatusOk <> ir Then
me.Output("conn.kStatusOk <> ir")
Return
End If
If frame.kFrameMethod = frame.FrameType Then
Select Case frame.MethodID
Case frame.kBasicAckMethod
//* If we've turned publisher confirms on, and we've published a
//* message here Is a message being confirmed.
//*/
Case frame.kBasicReturnMethod
//* If a published message couldn't be routed and the mandatory
//* flag was set this Is what would be returned. The message Then
//* needs To be read.
//*/
Dim message As RabbitMQMessageMBS
res = conn.ReadMessage(frame.channel, message)
If res.ResponseTypeNormal <> res.type Then
Return
End If
Case frame.kChannelCloseMethod
//* a channel.close method happens when a channel Exception occurs,
//* this can happen by publishing To an exchange that doesn't exist
//* For example.
//*
//* In this Case you would need To open another channel redeclare
//* any queues that were declared Auto-delete, And restart any
//* consumers that were attached To the previous channel.
//*/
return
Case frame.kConnectionCloseMethod
//* a connection.close method happens when a connection Exception
//* occurs, this can happen by trying To use a channel that isn't
//* open For example.
//*
//* In this Case the whole connection must be restarted.
//*/
return
Else
me.Output "An unexpected method was received: "+str(frame.MethodID)
Return
end Select
End If
End If
end if
app.DoEvents(100)
wend
me.Output("- conn.ChannelClose")
r = conn.ChannelClose(constChannel, RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
me.Output("- conn.ConnectionClose")
r = conn.ConnectionClose(RabbitMQRPCReplyMBS.kReplySuccess)
If Failed(r) Then Return
End Sub
Private Function WaitKeyInput(psOutput As String = "Weiter mit Return") As String
if (psOutput <> "") then
StdOut.Write(psOutput)
stdout.Flush()
end if
Dim sResult As String
Dim m As Double = Microseconds + 100000 'discard any "wait-to-be-read input"
while (Microseconds < m)
sResult = StdIn.Read(1)
wend
return sResult
End Function
Note "About"
RabbitMQ Tutorial project provided by Jürg Otter
Property Private AppRandom As Random
Property Private eiGuidNr As Integer
End Class
End Project
The items on this page are in the following plugins: MBS RabbitMQ Plugin.