Please direct all Support Questions and Concerns to Support@PubNub.com
www.pubnub.com - PubNub Real-time Push Service in the Cloud.
The PubNub Network is a blazingly fast Global Messaging Service for building real-time web and mobile apps. Thousands of apps and developers rely on PubNub for delivering human-perceptive real-time experiences that scale to millions of users worldwide. PubNub delivers the infrastructure needed to build amazing Mobile, MMO games, social apps, business collaborative solutions, and more.
Main change is that we're no longer using EventMachine. Right now Celluloid is used. Public API remain unchanged. If you encounter any issues while upgrading from EventMachine version, please contact us at support@pubnub.com you can also find eventmachine version in "eventmachine" branch of this repo.
We've made the response format compatible across all operations. This may break existing parsing of where_now, leave, state, and PAM responses. So if you are monitoring these operation responses, please be sure to modify your code accordingly.
Examples of affected operations can be found here.
PubNub 3.7.3 is NOT compatible with earlier than 3.4 versions of Pubnub Ruby Client.
Every operation is by default asynchronous (and it will return Celluloid Future). Asynchronous operations will not block your main thread and will be fired within a new thread.
This can cause issues under certain situations, depending on your implementation. To work around this, you can force an operation to run synchronously (block) via the :http_sync option:
http_sync: trueUnless otherwise specified, this option is default implied false (all calls by default will be async).
Results are provided via block, callback, and return, depending on how you structure the call. Callback will be fired for every message that will event get in response. Synchronous events will return array of envelopes (if you passed callback to sychronous event it will be called too!).
require'pubnub'# If you wish to override the default logger, create one and pass it in.# Default logger writes into pubnub.log filemy_logger=Logger.new(STDOUT)pubnub=Pubnub.new(subscribe_key: 'demo',publish_key: 'demo',error_callback: lambdado |msg|
puts"Error callback says: #{msg.inspect}"end,connect_callback: lambdado |msg|
puts"CONNECTED: #{msg.inspect}"end,logger: my_logger)- subscribe_key is your subscribe key
- publish_key is your publish key
- origin is your custom, PubNub origin (Contact support before production to get your own!)
- error_callback is the callback for errors
- connect_callback is the callback that lets you know when you're connected to the origin
There are a few different ways to make any given PubNub call. How to do it depends first on whether or not you want the call to be blocking (synchronous), or not blocking (asynchronous).
If you wish to make asyncronous calls, you have a few different patterns you can follow:
# Lets use a callback for the first example...cb=lambda{ |envelope| putsenvelope.message}# Asynchronous is implicitly enabled by default, if you do not provide an :http_sync optionpubnub.publish(message: msg,channel: channel,callback: cb)# You can also explicitly request sync with http_sync: truepubnub.publish(message: msg,channel: channel,callback: cb,http_sync: true)# Alternatively, you can pass in the callback as a blockpubnub.publish(message: msg,channel: channel, &cb)pubnub.publish(message: msg,channel: channel)do |envelope|
putsenvelope.messageputsenvelope.channelputsenvelope.status_codeputsenvelope.timetokenendIf you'd prefer to make your calls blocking, set :http_sync => true. Again, there is a bit of flexibility in how this can be done:
# Lets use a callback for the first example...cb=lambda{ |envelope| putsenvelope.message}# Sync (blocking) with a callback (if you wanted to)pubnub.publish(http_sync: true,message: msg,channel: channel, &cb)# Sync (blocking), with assignment via returnmy_response=pubnub.publish(http_sync: true,message: msg,channel: channel)puts"my response: #{my_response.inspect}"# Sync (blocking), with a blockpubnub.publish(http_sync: true,message: msg,channel: channel)do |envelope|
putsenvelope.messageputsenvelope.channelputsenvelope.status_codeputsenvelope.timetokenendWhen you receive messages asynchronously from PubNub, your block or callback will be called once for each message received. For example, if you are subscribed to a channel using the callback pattern, and you receive 3 messages from your call, the callback will be called 3 times, 1 time for each unique received message.
Conceptually, the callback or block is fired once for each message in the raw server response:
# simplifedenvelopes.eachdo |envelope|
callback.callenvelopeendThe callback (or block) will receive the message(s) in the form of an envelope hash. An envelope will contain the following keys:
- message (aliased as 'msg') -> Holds message, if publish, holds published message
- response_message -> as above, except for publish - holds server response (String "Send")
- channel -> Holds channel for current message
- wildcard_channel -> Holds wildcard channel for current message
- group -> Holds group for current message
- timetoken -> Timetoken of server response
- payload -> Payload from parsed_response
- service -> Service from parsed_response
- status (aliased as 'status_code') -> Server response status code
- response -> Whole and unmodified server response
- parsed_response -> Parsed server response
- first -> true if it's first envelope in single response messages array
- last -> true if it's last envelope in single response messages array
- And a bit more, specific to some events, you will find it in description of certain events
Don't confuse the message with the response. In a given callback cycle, the response will always be the same, as its the raw server response. It may consist of one or more messages.
Internally, the block or callback iterates over the response array, similar to:
envelopes.eachdo |envelope|
callback.callenvelope.messageendIn a given callback cycle, the envelope will be the current element of the response array.
pubnub=Pubnub.new(subscribe_key: 'demo',publish_key: 'demo',uuid: 'some-uniq-uuid',error_callback: lambda{ |msg|
puts"SOMETHING TERRIBLE HAPPENED HERE: #{msg.inspect}"},connect_callback: lambda{ |msg|
puts"CONNECTED: #{msg.inspect}"})When publishing, send a string, number, array, or hash. PubNub automatically serializes it to JSON for you, so you don't have to.
@my_callback=lambda{ |envelope| puts(envelope.msg)}pubnub.publish(channel: 'hello_world',message: 'hi',callback: @my_callback)pubnub.subscribe(channel: :hello_world,callback: @my_callback)Unsubscribes from given channel (:channel) or channel group (:group) and
fires leave event. You need to be subscribed to channel that
You want to leave.
pubnub.subscribe(channel: :hello_world,callback: @my_callback)pubnub.leave(channel: :hello_world,callback: @my_callback)If you want to force leave channel that you're not subscribed to, you can pass :force option to event
# Wrongpubnub.leave(channel: :not_subbed_channel,callback: @my_callback)# We'll get error:Pubnub::ArgumentError: Youcannotleavechannelthatis not subscribed# Goodp.leave(channel: :not_subbed_channel,force: true,callback: @my_callback)Retrieve previously published messages (requires activation via admin.pubnub.com) Optional start, end, and reverse option usage can be found in the tests.
pubnub.history(channel: channel,count: 10,callback: @my_callback)In real-time see people join and leave with occupancy summaries. (requires activation via admin.pubnub.com)
pubnub.presence(channel: :hello_world,callback: @my_callback)pubnub.presence(group: 'foo',callback: @my_callback)See who is "here now" in a channel (:channel) or channel group (:group) at this very moment.
pubnub.here_now(channel: channel,callback: @my_callback)pubnub.here_now(group: channel_group,callback: @my_callback)See where is client with specific uuid
p.where_now(uuid: :my_friend,callback: @my_callback)UUID is set in the initializer. A unique one is created, unless you specify one explicitly. To retrieve the current UUID:
pubnub.uuidIf you wish to manually set a custom UUID, pass in a uuid key in the initializer. See "Init and instantiate a new PubNub instance" for an example.
Get the current PubNub time. This is great to use as a "PubNub Ping"
pubnub.time(callback: @my_callback)Channel grouping is new feature introduced in Pubnub 3.7. It allows to group
channels into channel-groups. For example you can add weather and sport
channel to news channel group.
All channel groups specific operations can be issued with
#channel_registration method.
# Response envelope will hold info as hash in payload attribute.pubnub.channel_registration(action: :list_groups,http_sync: true)# Response envelope will hold info as hash in payload attribute.pubnub.channel_registration(action: :get,group: 'foo',http_sync: true)pubnub.channel_registration(action: :add,group: 'new_group',channel: :bot,http_sync: true)pubnub.channel_registration(action: :remove,group: 'cg',http_sync: true)pubnub.channel_registration(action: :remove,group: 'cg',channel: :to_remove,http_sync: true)Developers can grant/revoke/audit fine-grained permissions for their real-time apps and data at various levels.
Envelopes returned by PAM events have additional :service and :payload keys.
When you issue a PAM operation, you can pass the presence key, the 'channel' key, or both.
# Will grant :r, :w and :m permissions to demo-pnpres channelpubnub.grant(presence: :demo)do |envelope|
putsenvelope.messageend# Will grant :r, :w and :m permissions to demo channelpubnub.grant(channel: :demo)do |envelope|
putsenvelope.messageend# Will grant :r, :w and :m permissions to demo and demo-pnpres channelspubnub.grant(presence: :demo,channel: :demo)do |envelope|
putsenvelope.messageend# For channel groups, all above work.# Will grant :r, :w and :m permissions to foopubnub.grant(:group=>'foo')do |envelope|
putsenvelope.messageendAudits auths for given parameters
pubnub.audit(channel: :forbidden_for_jim)do |envelope|
putsenvelope.payloadendpubnub.audit(channel: :forbidden_for_jim,auth_key: :jim)do |envelope|
putsenvelope.payloadendGrants auths for given parameters, you can pass :read and :write keys as parameters
pubnub.grant(channel: :forbidden_to_write,read: true,write: false)do |envelope|
putsenvelope.payloadendpubnub.grant(channel: :forbidden_to_write,read: true,write: true,:auth_key=>:admin)do |envelope|
putsenvelope.payloadendRevokes right to read and write. Same as granting r:0 w:0.
pubnub.revoke(channel: :forbidden)do |envelope|
putsenvelope.payloadendpubnub.grant(channel: :forbidden,auth_key: :godzilla)do |envelope|
putsenvelope.payloadend# Example below shows passing more options for client# Pubnub.new returns Pubnub::Client instancepubnub=Pubnub.new(error_callback: custom_error_callback,connect_callback: custom_connect_callback,ssl: true,uuid: 'newton',subscribe_timeout: 500,non_subscribe_timeout: 15,ttl: custom_default_ttl_for_pam,secret_key: 0)You can find more default values in Pubnub::Configuration, you can overwrite them passing it while initializing.
You can pass your custom logger as :logger key while creating new Pubnub instance. Logger invocations has set progname 'Pubnub::Class' eg. 'Pubnub::Client', 'Pubnub::Subscribe'.
# Message could be any object that have .to_json method# You do not need to jsonify message before sending!# This time publish event will block main thread until callback will finish as we set :http_sync to truepubnub.publish(messsage: message,channel: :whatever,http_sync: true)# You can pass in :channel or :channels String, Symbol, Array of both, or csv separated with commas, remember, as space is valid channel part, there should not be any spaces between commas (unless you want them)# Some example of valid channels:# :example_symbol# 'example_string'# [:one, :two, 'three']# [:anything]# 'one,two,three'# Firing sync subscribe could lock your thread even for 5 minutes# When there's no traffic on channel server will send timetoken without# any messages every ~300s.# First sync subscribe will just update your timetoken, you will not get any messages# example:pubnub.subscribe(channel: 'alerts',http_sync: true)# just update timetokenpubnub.subscribe(channel: 'alerts',http_sync: true)# Will fire request with current timetoken and can possibly get messages# Async subscribe will update your timetoken and will fire given callback for every message that it gets# example:pubnub.subscribe(channel: 'fight_log')do |envelope|
putsenvelope.message['attacker']putsenvelope.message['defender']putsenvelope.message['damage']endYou can subscribe to channel group same way as You're subscribing to channels.
pubnub.subscribe(group: 'foo',channel: :ping_3,callback: callback)Response envelopes will hold channel and channel_group values. So, if You want
to subscribe to channel group and your callback need to know where are envelopes
from, You can check it using envelope.channel_group. Of course You can
subscribe to channel group and plain channel at once.
History returns :count messages from given channel.
pubnub.history(channel: :actions,count: 10,start: 13942156708212448,end: 13942156908212448,callback: replay):reverse set to true will traverse the time line in reverse starting with the newest message first. Default is false. If both start and end arguments are provided, reverse is ignored and messages are returned starting with the newest message.
pubnub.history(channel: :actions,count: 10,reverse: true,callback: replay)History envelope also contains .history_start and .history_end values
Paginate through your history. You can pass :channel, :page, :limit, :callback, :http_sync, :start and :end options, all of them works like in history event.
pubnub.paged_history(channel: :actions,limit: 10,page: 3,http_sync: true)Presence works exactly the same way as subscribe, it just adds '-pnpres' to channel name.
pubnub.presence(channel: :mars)do |envelope|
show_in_roster(envelope.uuid)endHereNow shows us who is currently subscribing channel and how much clients are online on given channel.
pubnub.here_now(channel: :pamam_moon_iv)do |envelope|
putsenvelope.parsed_response['uuids']putsenvelope.parsed_response['occupancy']endYou can also give no specific channel. Then you'll get global HereNow event response which holds all channels.
pubnub.here_now{ |envelope| putsenvelope.parsed_response['channels']}Heartbeat (expressed in seconds) is used to signal to the server that the client is still online. If the client disconnects without a leave event, others observing presence on the channel will not notice that this client has left the channel until a maximum of heartbeat interval seconds.
You normally will never need to touch this value, unless your Ruby client resides on a poor or mobile connection.
pubnub=Pubnub.new(subscribe_key: 'demo',heartbeat: 60)Update it via heartbeat=
pubnub.heartbeat=120Read it via heartbeat
pubnub.heartbeatPAM allows you to grant read and write access basing on channels and auth_keys. Every pam event requires :secret_key (Remember! You should set it while initializing pubnub)
PAM actions could take :presence option, that will grant/revoke/audit permissions on given presence channel. :presence option can be used along with :channel.
pubnub.audit(channel: 'hidden_system'){ |envelope| putsenvelope.msg}# Channel levelpubnub.grant(channel: 'hidden_system',read: true,write: false){ |envelope| putsenvelope.msg}# Auth key levelpubnub.grant(channel: 'hidden_system',read: true,write: false,auth_key: :lemon){ |envelope| putsenvelope.msg}Revoke is equal to grant with w false, read false
# Channel levelpubnub.revoke(channel: 'hidden_system'){ |envelope| putsenvelope.msg}# Auth key levelpubnub.revoke(channel: 'hidden_system',auth_key: :lemon){ |envelope| putsenvelope.msg}State is stored on the server for subscribed uuid, you can pass state in few ways and you can get it from server.
# You can set state in a few ways# Using subscribepubnub.subscribe(channel: 'my_channel',state: {:my_channel=>{:key=>:value}}){ |e| putse.msg}# Be aware that state have to be hash of hashes where keys are subscribed channel names# Using event #set_statepubnub.set_state(state: {key: :value},channel: :my_channel)# or with channel groupspubnub.set_state(state: {:key=>:value},group: 'foo')# All you need to know is just uuid and channelpubnub.state(uuid: 'uuid_client_that_i_am_searching_for')Basic proxy is supported using ENV global, before initializing pubnub just set:
ENV['HTTP_PROXY']='http://my.poxy/'ENV['HTTP_PROXY_USER']='user'ENV['HTTP_PROXY_PASS']='secret'after that you can initialize pubnub object as always.