Permalink
Browse files

Added a full-feature example with public, private, and presence chann…

…els.
  • Loading branch information...
1 parent 886d27d commit afd9336c95006e8fc91f440b03a3def6f8f8be03 @bennadel committed Aug 21, 2012
Showing with 381 additions and 0 deletions.
  1. +74 −0 examples/all_features/Application.cfc
  2. +95 −0 examples/all_features/channel_auth.cfm
  3. +212 −0 examples/all_features/index.cfm
@@ -0,0 +1,74 @@
+<cfscript>
+
+component
+ output = "false"
+ hint = "I define the application settings and event handlers."
+ {
+
+
+ // Define the application settings.
+ this.name = hash( getCurrentTemplatePath() );
+ this.applicationTimeout = createTimeSpan( 0, 0, 10, 0 );
+
+ // Enable session management so we can have CFID/CFTOKEN values.
+ this.sessionManagement = true;
+ this.sessionTimeout = createTimeSpan( 0, 0, 1, 0 );
+
+ // Get the current directory and the root directory so that we can
+ // set up the mappings to our components.
+ this.appDirectory = getDirectoryFromPath( getCurrentTemplatePath() );
+ this.projectDirectory = (this.appDirectory & "../../");
+
+ // Map to our Lib folder so we can access our project components.
+ this.mappings[ "/lib" ] = (this.projectDirectory & "lib/");
+
+ // Map to our Vendor folder so we can access 3rd-party components.
+ this.mappings[ "/vendor" ] = (this.projectDirectory & "vendor/");
+
+
+ // I initialize the session.
+ function onSessionStart(){
+
+ // Store some information about the user that we can pass
+ // through to the Presence channel.
+ session.user = {
+ id = 4,
+ name = "Tricia"
+ };
+
+ }
+
+
+ // I initialize the request.
+ function onRequestStart(){
+
+ // Store the credentials for the Pusher App API.
+ // *********************************************************
+ // THESE ARE DEMO CREDENTIALS AND SHOULD NOT BE USED IN YOUR
+ // PRODUCTION APP; THEY ARE FOR SANDBOX USE AND HAVE HARD
+ // LIMITS ON CONNECTIONS AND MESSAGES. SWAP THESE OUT WHEN
+ // YOU IMPLEMENT THIS LIBRARY.
+ // *********************************************************
+ request.pusherAppID = "1577";
+ request.pusherKey = "967025141727846f5a79";
+ request.pusherSecret = "5a7fd901cdf3e73c18b5";
+ // *********************************************************
+
+ // Create an instance of our pusher component using our demo
+ // credentials and the Crypto library.
+ request.pusher = new lib.Pusher(
+ appID = request.pusherAppID,
+ appKey = request.pusherKey,
+ appSecret = request.pusherSecret,
+ crypto = new vendor.crypto.Crypto()
+ );
+
+ // Return true so the page can load.
+ return( true );
+
+ }
+
+
+}
+
+</cfscript>
@@ -0,0 +1,95 @@
+
+<!---
+ I provide the authentication for connecting to both private
+ channels and presence channels. Both channels use the same
+ authentication approach; however, the presence channel requires
+ additional return data.
+--->
+
+<!--- Param the form fields. --->
+<cfparam name="form.channel_name" type="string" />
+<cfparam name="form.socket_id" type="string" />
+
+<!---
+ We are also expecting the userID to come through with all
+ authentication-based requests (due to our connection configuration).
+--->
+<cfparam name="form.userID" type="numeric" />
+
+
+<!--- ----------------------------------------------------- --->
+<!--- ----------------------------------------------------- --->
+
+
+<!--- Check to make sure the given userID matches. --->
+<cfif (form.userID neq session.user.id)>
+
+ <!---
+ The user is trying to subscribe to a channel that they are
+ not allowed to.
+ --->
+ <cfheader
+ statuscode="403"
+ statustext="Forbidden"
+ />
+
+ <!--- Halt any further processing. --->
+ <cfabort />
+
+</cfif>
+
+
+<!--- ----------------------------------------------------- --->
+<!--- ----------------------------------------------------- --->
+
+
+<!---
+ Check to see if this is a Private channel or a Presence channel
+ authentication request.
+--->
+<cfif reFind( "^presence-", form.channel_name )>
+
+ <!--- Presence channel. --->
+
+ <!---
+ When authenticating a presence channel subscription, we need
+ to pass along additional user-data to Pusher. The "user_id"
+ value is required. The "user_info" value is optional and may
+ contain any additional data you want to pass to the channel.
+ All of these values will be published to the presence channel
+ for clients to consume.
+ --->
+ <cfset channelData = {
+ "user_id" = session.user.id,
+ "user_info" = {
+ "name" = session.user.name
+ }
+ } />
+
+ <cfset authentication = request.pusher.getPresenceChannelAuthentication(
+ form.socket_id,
+ form.channel_name,
+ channelData
+ ) />
+
+<cfelse>
+
+ <!--- Private channel. --->
+
+ <cfset authentication = request.pusher.getPrivateChannelAuthentication(
+ form.socket_id,
+ form.channel_name
+ ) />
+
+</cfif>
+
+
+<!--- The authentication response is expected in JSON format. --->
+<cfset serializedResponse = serializeJSON( authentication ) />
+
+<!--- Stream respones back to the client. --->
+<cfcontent
+ type="application/json"
+ variable="#toBinary( toBase64( serializedResponse ) )#"
+ />
+
@@ -0,0 +1,212 @@
+
+<cfoutput>
+
+ <!doctype html>
+ <html>
+ <head>
+ <meta charset="utf-8" />
+
+ <title>Pusher.com ColdFusion Feature Demo</title>
+
+ <!-- Include jQuery and Pusher libraries from the CDN. -->
+ <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
+ <script type="text/javascript" src="http://js.pusher.com/1.12/pusher.min.js"></script>
+
+ </head>
+ <body>
+
+ <h1>
+ Pusher.com ColdFusion Feature Demo
+ </h1>
+
+ <ol class="pusherLog">
+ <!-- To be populated dynamically. -->
+ </ol>
+
+ <p>
+ <em>Wait a few seconds for test messages from CFThread.</em>
+ </p>
+
+
+ <!-- Run the page scripts. -->
+ <script type="text/javascript">
+
+
+ // Store the pusher App key - we'll need this when we connect.
+ var pusherAppKey = "#request.pusherKey#";
+
+ // Create a new instance of the Pusher client. The second
+ // argument - the connection options - is an optional set
+ // of data that can be passed through with Authentication
+ // requests. In this case, we are going to be passing the
+ // session-based USERID through so we can validate it
+ // against the current session.
+ var pusher = new Pusher(
+ pusherAppKey,
+ {
+ auth: {
+ params: {
+ "userID": "#session.user.id#"
+ }
+ }
+ }
+ );
+
+ // For Private and Presence channel workflows, we need to
+ // define a server-side end-point where the Pusher client
+ // can get additional authorization. This is accessed from
+ // the client-side, not from the Pusher servers.
+ Pusher.channel_auth_endpoint = "./channel_auth.cfm"
+
+
+ // Define a log method for writing events to the HTML.
+ var logEvent = function( message ){
+
+ $( "ol.pusherLog" ).append(
+ ("<li>" + message + "</li>")
+ );
+
+ };
+
+
+ // Liste for state changes on the pusher client.
+ pusher.connection.bind(
+ "state_change",
+ function( states ){
+
+ logEvent( "Connection State: " + states.current );
+
+ }
+ );
+
+
+ // Listen for a connection event.
+ pusher.connection.bind(
+ "connected",
+ function(){
+
+ logEvent( "Connected with Socket ID " + pusher.connection.socket_id );
+
+ }
+ );
+
+
+ // Let's subscribe to a presence channel - tehse are channels
+ // prefixed with the term, "presence-". There is no need to
+ // wait for Pusher to finish connecting to the server - we
+ // can subscribe at any time.
+ var presenceChannel = pusher.subscribe( "presence-demo-channel" );
+
+ // Listen for
+ presenceChannel.bind(
+ "pusher:subscription_succeeded",
+ function( members ){
+
+ logEvent( "Presence Channel Subscribed: " + members.count + " members." );
+
+ // Output the member info on the channel.
+ members.each(
+ function( member ){
+
+ logEvent( "--- [" + member.id + "] " + member.info.name );
+
+ }
+ );
+
+ }
+ );
+
+ // Listen for events on the channel.
+ presenceChannel.bind(
+ "pusher:member_added",
+ function( member ){
+
+ logEvent( "I sense a new presence: " + member.name );
+
+ }
+ );
+
+
+ // Let's subscribe to a prviate channel - these are channels
+ // prefixed with the term, "private-". There is no need to
+ // wait for Pusher to finish connecting to the server - we
+ // can subscribe at any time.
+ var privateChannel = pusher.subscribe( "private-demo-channel" );
+
+ // Listen for events on the channel.
+ privateChannel.bind(
+ "message",
+ function( message ){
+
+ logEvent( "New Private Message: " + message.text );
+
+ }
+ );
+
+
+ // Let's subscribe to a public channel.
+ var publicChannel = pusher.subscribe( "app-channel" );
+
+ // Listen for events on the channel.
+ publicChannel.bind(
+ "message",
+ function( message ){
+
+ logEvent( "New Public Message: " + message.text );
+
+ }
+ );
+
+
+ </script>
+
+ </body>
+ </html>
+
+
+ <!--- ------------------------------------------------- --->
+ <!--- ------------------------------------------------- --->
+ <cfflush />
+ <!--- ------------------------------------------------- --->
+ <!--- ------------------------------------------------- --->
+
+
+ <!---
+ Now, let's create an asynchronous thread and push a message
+ down to the user.
+ --->
+ <cfthread
+ name="pushMessage"
+ action="run">
+
+ <!--- Sleep briefly to give Pusher time to connect. --->
+ <cfset sleep( 3 * 1000 ) />
+
+ <!--- Create a PRIVATE message. --->
+ <cfset message = {
+ "text" = "Ah, Push it! Push it real good!"
+ } />
+
+ <!--- Push the message down the private channel. --->
+ <cfset request.pusher.pushToAllSubscribers(
+ channel = "private-demo-channel",
+ eventType = "message",
+ message = message
+ ) />
+
+
+ <!--- Create a PUBLIC message. --->
+ <cfset message = {
+ "text" = "Something less secure just happened!"
+ } />
+
+ <!--- Push the message down the public channel. --->
+ <cfset request.pusher.pushToAllSubscribers(
+ channel = "app-channel",
+ eventType = "message",
+ message = message
+ ) />
+
+ </cfthread>
+
+</cfoutput>

0 comments on commit afd9336

Please sign in to comment.