Skip to content

Instantly share code, notes, and snippets.

@cfmitrah
Last active March 11, 2019 08:20
Show Gist options
  • Save cfmitrah/6aecb8b398968680267dadba9afcd044 to your computer and use it in GitHub Desktop.
Save cfmitrah/6aecb8b398968680267dadba9afcd044 to your computer and use it in GitHub Desktop.
Demo Lucee Event Gateway - Driver Component
<cfcomponent output="no">
<cfset variables.logFileName = "demoLogGateway" />
<cfset variables.state="stopped" />
<cffunction name="init" access="public" output="no" returntype="void">
<cfargument name="id" required="false" type="string">
<cfargument name="config" required="false" type="struct">
<cfargument name="listener" required="false" type="component">
<cfset variables.id=id>
<cfset variables.config=config>
<cfset variables.listener=listener>
</cffunction>
<cffunction name="start" access="public" output="no" returntype="void">
<cfset var sleepStep = iif(variables.config.interval lt 500, 'variables.config.interval', de(500)) />
<cfset var i=-1 />
<cfwhile variables.state EQ "stopping">
<!--- Loop & wait for 10 ms, until gateway is running --->
<cfset sleep(10)>
</cfwhile>
<cfset variables.state="running">
<cfset variables._filter = cleanExtensions(variables.config.extensions) />
<cfset logDetails("start", "information")>
<cfset var funcNames={add:config.addFunction, change:config.changeFunction, delete:config.deleteFunction}>
<!--- check if the directory actually exists --->
<cfif not DirectoryExists(variables.config.directory)>
<cfset logDetails("Directory [#variables.config.directory#] does not exist or is not a directory", "error")>
</cfif>
<cfif not StructKeyExists(variables.config,"recurse")>
<cfset variables.config.recurse=false>
</cfif>
<cfset var files=loadFiles(variables.config.directory, variables.config.recurse, variables._filter) />
<!--- first execution --->
<cfwhile variables.state EQ "running">
<cfset var coll=compareFiles(files,funcNames,config.directory, config.recurse, variables._filter)>
<cfset files=coll.data>
<cfset var name="">
<cfset var funcName="">
<cfloop collection="#coll.diff#" item="name">
<cfset funcName=coll.diff[name].action>
<cfif len(funcName)>
<!--- calling listener methods --->
<cfset logDetails("change:::#funcName#:::#name#:::start", "information")>
<cfset variables.listener[funcName](coll.diff[name])>
<cfset logDetails("change:::#funcName#:::#name#:::done", "information")>
</cfif>
</cfloop>
<cfif variables.state NEQ "running">
<cfbreak />
</cfif>
<!--- sleep untill the next run, but cut it into half seconds, so we can stop the gateway --->
<cfloop from="#sleepStep#" to="#variables.config.interval#" step="#sleepStep#" index="i">
<cfset sleep(sleepStep) />
<cfif variables.state neq "running">
<cfbreak />
</cfif>
</cfloop>
<!--- some extra sleeping if --->
<cfif variables.config.interval mod sleepStep and variables.state eq "running">
<cfset sleep((variables.config.interval mod sleepStep)) />
</cfif>
</cfwhile>
<cfset variables.state="stopped" />
</cffunction>
<cffunction name="loadFiles" access="private" output="no" returntype="struct" hints="Loads the current details of available files">
<cfargument name="directory" type="string" required="yes">
<cfargument name="recurse" type="boolean" required="no" default="#false#">
<cfargument name="fileFilter" type="string" required="no" default="*" />
<cfset var dir = getFiles(arguments.directory, arguments.recurse, arguments.fileFilter) />
<cfset var sct={} />
<cfloop query="dir">
<cfset sct[dir.directory&server.separator.file&dir.name] = createElement(dir) />
</cfloop>
<cfreturn sct />
</cffunction>
<cffunction name="getFiles" access="private" output="no" returntype="query" hints="List all files in the specified directory with applied filters">
<cfargument name="directory" type="string" required="yes">
<cfargument name="recurse" type="boolean" required="no" default="false" />
<cfargument name="fileFilter" type="string" required="no" default="*" />
<cfset var qDir = "" />
<cfdirectory directory="#arguments.directory#" action="list" name="qDir" type="file"
filter="#arguments.fileFilter#" recurse="#arguments.recurse#" />
<cfreturn qDir />
</cffunction>
<cffunction name="compareFiles" access="private" output="no" returntype="struct">
<cfargument name="last" type="struct" required="yes">
<cfargument name="funcNames" type="struct" required="yes">
<cfargument name="directory" type="string" required="yes">
<cfargument name="recurse" type="boolean" required="no" default="false" />
<cfargument name="fileFilter" type="string" required="no" default="*" />
<cfset var dir = getFiles(arguments.directory, arguments.recurse, arguments.fileFilter) />
<cfset var sct={}>
<cfset var diff={}>
<cfset var name="">
<cfset var tmp="">
<!--- check for new and changed files --->
<cfloop query="dir">
<cfset name=dir.directory&server.separator.file&dir.name>
<!--- populate the struct with all currently found files/directories --->
<cfset sct[name]=createElement(dir)>
<!--- file existed already --->
<cfif StructKeyExists(arguments.last,name)>
<!--- date last modified has changed? --->
<cfif dir.dateLastModified NEQ arguments.last[name].dateLastModified>
<cfset tmp = createElement(dir)>
<cfset tmp.action = arguments.funcNames.change>
<cfset diff[name] = tmp>
</cfif>
<!--- new file --->
<cfelse>
<cfset tmp=createElement(dir)>
<cfset tmp.action=funcNames.add>
<cfset diff[name]=tmp>
</cfif>
</cfloop>
<!--- check if files are deleted --->
<cfloop collection="#last#" item="name">
<cfif not StructKeyExists(sct,name)>
<cfset last[name].action=funcNames.delete>
<cfset diff[name]=last[name]>
</cfif>
</cfloop>
<cfreturn {data:sct,diff:diff}>
</cffunction>
<cffunction name="createElement" access="private" output="no" returntype="struct">
<cfargument name="dir" type="query" required="yes">
<cfreturn {dateLastModified:dir.dateLastModified, size:dir.size, name:dir.name, directory:dir.directory,id:variables.id}>
</cffunction>
<cffunction name="stop" access="public" output="no" returntype="void">
<cfset logDetails("stop", "information")>
<cfset variables.state="stopping">
</cffunction>
<cffunction name="restart" access="public" output="no" returntype="void">
<cfif state EQ "running"><cfset stop()></cfif>
<cfset start()>
</cffunction>
<cffunction name="getState" access="public" output="no" returntype="string">
<cfreturn variables.state />
</cffunction>
<cffunction name="sendMessage" access="public" output="no" returntype="string">
<cfargument name="data" required="true" type="struct">
<cfset variables.listener.checkChange(arguments.data)>
<cfreturn true>
</cffunction>
<cffunction name="cleanExtensions" access="private" output="no" returntype="string">
<cfargument name="extensions" required="true" type="string">
<!--- replace the commas and optional trailing spaces with pipes ("|"), because that's the delimiter cfdirectory works with. --->
<cfreturn rereplace(trim(arguments.extensions), " *, *", "|", "all") />
</cffunction>
<cffunction name="_handleError" returntype="void" access="private" output="no">
<cfargument name="catchData" required="yes" />
<cfargument name="functionName" type="string" required="no" default="unknown" />
<cfset logDetails("Function #arguments.functionName#: #arguments.catchData.message# #arguments.catchData.detail#", "error")>
</cffunction>
<cffunction name="logDetails" returntype="void" access="private" output="no">
<cfargument name="content" required="yes" type="string" />
<cfargument name="type" required="yes" type="string" />
<cflog text="#arguments.content#" type="#arguments.type#" file="#variables.logFileName#" />
</cffunction>
</cfcomponent>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment