Created
March 25, 2014 11:40
Communicating With The Client Whilst Inside A ColdFusion Custom Tag
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- | |
Since we are waiting for our thread in parallel, let's increase | |
the page timeout to ensure we can process the response. | |
---> | |
<cfsetting requesttimeout="60" /> | |
<!--- I am the name of the thread we are going to execute. ---> | |
<cfset request.threadName = "testThread#randRange( 1111, 9999 )#" /> | |
<!--- | |
I am the status variable (this is what the thread is going to | |
update as it processes). | |
---> | |
<cfset request[ "#request.threadName#_status" ] = "-" /> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<!--- | |
Define a function that we will pass into the thread to allow it | |
to report progress without having to know much about how this is | |
being echoed to the client. | |
---> | |
<cffunction | |
name="reportProgress" | |
access="public" | |
returntype="string" | |
output="false" | |
hint="I report the progress of the given thread."> | |
<!--- Define arguments. ---> | |
<cfargument | |
name="status" | |
type="string" | |
required="true" | |
hint="I am the status of the calling context." | |
/> | |
<!--- Update the progress status in the request. ---> | |
<cfset request[ "#request.threadName#_status" ] = arguments.status /> | |
<!--- Return out. ---> | |
<cfreturn /> | |
</cffunction> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<!--- | |
Launch our async thread. Notice that we are passing a reference | |
to our status update method into thread for it to use. | |
NOTE: We are also passing-in the file name that we want the given | |
thread to output it's content to. | |
---> | |
<cfthread | |
name="#request.threadName#" | |
action="run" | |
reportprogress="#reportProgress#" | |
filename="#expandPath( './#createUUID()#.txt' )#"> | |
<!--- | |
Pass controll off to the custom tag. Notice that with a | |
custom tag, we cannot typically FLUSH output to the client | |
during its execution. However, since this is executing inside | |
a CFThread, it is now in a differnt output buffer. | |
---> | |
<cf_generatedocument | |
filename="#attributes.fileName#" | |
reportprogress="#attributes.reportProgress#" | |
/> | |
<!--- | |
Once the document has been gernated, let's just store the | |
file name back in the thread result so the parent page can | |
reference it. | |
---> | |
<cfset thread.fileName = attributes.fileName /> | |
</cfthread> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<cfoutput> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Your Document Is Being Generated</title> | |
</head> | |
<body> | |
<h1> | |
Your Document Is Being Generated | |
</h1> | |
<p> | |
Progress: | |
<span id="documentProgrress"> | |
<!--- This is where we will output updates. ---> | |
</span> | |
</p> | |
<!--- --------------------------------------------- ---> | |
<!--- --------------------------------------------- ---> | |
<!--- --------------------------------------------- ---> | |
<!--- --------------------------------------------- ---> | |
<!--- Flush the current output to the client. ---> | |
<cfflush /> | |
<!--- Get the current status. ---> | |
<cfset currentStatus = "" /> | |
<!--- Keep looping until the thread is finished. ---> | |
<cfloop condition="(cfthread[ request.threadName ].status neq 'COMPLETED')"> | |
<!--- Check to see if the status has been updated. ---> | |
<cfif (currentStatus neq request[ "#request.threadName#_status" ])> | |
<!--- Update the document using the status variable. ---> | |
<script type="text/javascript"> | |
document | |
.getElementById( "documentProgrress" ) | |
.innerHTML = "#request[ '#request.threadName#_status' ]#" | |
; | |
</script> | |
<!--- | |
Save the current status so we don't get duplicate | |
output (in the source code). | |
---> | |
<cfset currentStatus = request[ "#request.threadName#_status" ] /> | |
<!--- | |
Flush the update to the client so the document | |
actually updates. | |
---> | |
<cfflush /> | |
<!--- | |
Sleep for a few milliseconds to let the document | |
have a change to update. | |
---> | |
<cfthread | |
action="sleep" | |
duration="100" | |
/> | |
</cfif> | |
</cfloop> | |
<!--- | |
Now that the thread has completed, forward user to the | |
generated file. | |
---> | |
<script type="text/javascript"> | |
location.href = "#getFileFromPath( cfthread[ request.threadName ].fileName )#"; | |
</script> | |
</body> | |
</html> | |
</cfoutput> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- Param the tag attributes. ---> | |
<cfparam | |
name="attributes.fileName" | |
type="string" | |
/> | |
<cfparam | |
name="attributes.reportProgress" | |
type="any" | |
/> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<!--- Create a buffer to hold our file content. ---> | |
<cfset buffer = [] /> | |
<!--- Create 1000 lines in our file. ---> | |
<cfloop | |
index="lineIndex" | |
from="1" | |
to="1000" | |
step="1"> | |
<!--- Append the line to the buffer. ---> | |
<cfset arrayAppend( | |
buffer, | |
"Hey this is line #lineIndex# of my file!" | |
) /> | |
<!--- Report progress. ---> | |
<cfset attributes.reportProgress( | |
"#lineIndex# lines have been written to this file." | |
) /> | |
<!--- | |
To mimic something that is actually processing intensive, | |
sleep this thread for a bit. | |
---> | |
<cfthread | |
action="sleep" | |
duration="5" | |
/> | |
</cfloop> | |
<!--- Report file completion. ---> | |
<cfset attributes.reportProgress( | |
"Your file has been successfully generated!" | |
) /> | |
<!--- Write the content to file. ---> | |
<cfset fileWrite( | |
attributes.fileName, | |
arrayToList( buffer, (chr( 13 ) & chr( 10 )) ) | |
) /> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<!--- Exist out of tag. ---> | |
<cfexit method="exitTag" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment