- Classroom file watcher was not working as expected because lastModifiedTime of a directory is not updated when a file is changed inside it.

- Added functions watchDir/unwatchDir which is responsible for watching all files and subdirectories changes
- Callback is called once for each detected change
- Changed classroom to check for the last "refresh" made to avoid multiple refreshes without changes
- Changed refresh time to 3s because it is much more comfortable
  - I don't think this would be an issue because checking for lastModifiedTime should be very fast, perhaps even 3s is too much time
- Tested in Windows
This commit is contained in:
Tiago Freitas 2014-06-28 13:32:55 +01:00
parent bded5e8bd5
commit b480922b15
2 changed files with 145 additions and 10 deletions

View file

@ -517,15 +517,67 @@ utils.watchFile( 'test.txt', function( file ) {
``` ```
***/ ***/
var filesWatched = {}; var filesWatched = {};
var dirsWatched = {};
exports.watchFile = function( file, callback ) { exports.watchFile = function( file, callback ) {
if ( typeof file == 'string' ) { if ( typeof file == 'string' ) {
file = new File(file); file = new File(file);
} }
//console.log("Watching file " + file);
filesWatched[file.canonicalPath] = { filesWatched[file.canonicalPath] = {
callback: callback, callback: callback,
lastModified: file.lastModified() lastModified: file.lastModified()
}; };
}; };
/************************************************************************
### utils.watchDir() function
Watches for changes to the given directory and calls the function provided
when the directory changes. It works by calling watchFile/watchDir for each
file/subdirectory.
#### Parameters
* Dir - the file to watch (can be a file or directory)
* Callback - The callback to invoke when the directory has changed.
The callback takes the changed file as a parameter.
For each change inside the directory the callback will also
be called.
#### Example
```javascript
var utils = require('utils');
utils.watchDir( 'players/_ial', function( dir ) {
console.log( dir + ' has changed');
});
```
***/
exports.watchDir = function( dir, callback ) {
if ( typeof dir == 'string' ) {
dir = new File(dir);
}
//console.log("Watching dir " + dir);
dirsWatched[dir.canonicalPath] = {
callback: callback,
lastModified: dir.lastModified()
};
var files = dir.listFiles(),file;
if ( !files ) {
return;
}
for ( var i = 0; i < files.length; i++ ) {
file = files[i];
if (file.isDirectory( )) {
exports.watchDir(file,callback);
}else{
exports.watchFile(file,callback);
}
}
};
/************************************************************************ /************************************************************************
### utils.unwatchFile() function ### utils.unwatchFile() function
@ -542,21 +594,98 @@ exports.unwatchFile = function( file, callback ) {
if ( typeof file == 'string' ) { if ( typeof file == 'string' ) {
file = new File(file); file = new File(file);
} }
//console.log("Unwatching file " + file);
delete filesWatched[file.canonicalPath]; delete filesWatched[file.canonicalPath];
}; };
function fileWatcher() { /************************************************************************
### utils.unwatchDir() function
Removes a directory from the watch list and all files inside the directory
are also "unwatched"
#### Example
```javascript
var utils = require('utils');
utils.unwatchDir ('players/_ial');
```
Would cause also
```javascript
utils.unwatchFile (file);
```
for each file inside directory (and unwatchDir for each directory inside it)
***/
exports.unwatchDir = function( dir, callback ) {
if ( typeof dir == 'string' ) {
dir = new File(dir);
}
//console.log("Unwatching dir " + dir);
delete dirsWatched[dir.canonicalPath];
var files = dir.listFiles(),file;
if ( !files ) {
return;
}
for ( var i = 0; i < files.length; i++ ) {
file = files[i];
if (file.isDirectory( )) {
exports.unwatchDir(file,callback);
}else{
exports.unwatchFile(file,callback);
}
}
};
function fileWatcher(calledCallbacks) {
for (var file in filesWatched) { for (var file in filesWatched) {
var fileObject = new File(file); var fileObject = new File(file);
var lm = fileObject.lastModified(); var lm = fileObject.lastModified();
if ( lm != filesWatched[file].lastModified ) { if ( lm != filesWatched[file].lastModified ) {
//console.log("Change found in " + file);
filesWatched[file].lastModified = lm; filesWatched[file].lastModified = lm;
filesWatched[file].callback(fileObject); filesWatched[file].callback(fileObject);
if (!fileObject.exists()) {
//console.log("File " + file + " was removed.");
exports.unwatchFile(file,filesWatched[file].callback);
}
} }
} }
setTimeout( fileWatcher, 5000 );
}; };
setTimeout( fileWatcher, 5000 );
//monitors directories for time change
//when a change is detected watchFiles are invoked for each of the files in directory
//and callback is called
function dirWatcher(calledCallbacks) {
for (var dir in dirsWatched) {
var dirObject = new File(dir);
var lm = dirObject.lastModified();
var dw = dirsWatched[dir];
if ( lm != dirsWatched[dir].lastModified ) {
//console.log("Change found in " + dir);
dirsWatched[dir].lastModified = lm;
dirsWatched[dir].callback(dirObject);
exports.unwatchDir(dir, dw.callback);
//causes all files to be rewatched
if (dirObject.exists()) {
exports.watchDir(dir, dw.callback);
} else {
//console.log("Directory " + dir + " was removed.");
}
}
}
};
//guarantees that a callback is only called once for each change
function monitorDirAndFiles() {
fileWatcher ();
dirWatcher ();
setTimeout( monitorDirAndFiles, 3000 );
};
setTimeout( monitorDirAndFiles, 3000 );
/************************************************************************** /**************************************************************************
### utils.array() function ### utils.array() function

View file

@ -2,8 +2,8 @@ var utils = require('utils'),
autoload = require('plugin').autoload, autoload = require('plugin').autoload,
logger = __plugin.logger, logger = __plugin.logger,
foreach = utils.foreach, foreach = utils.foreach,
watchFile = utils.watchFile, watchDir = utils.watchDir,
unwatchFile = utils.unwatchFile, unwatchDir = utils.unwatchDir,
playersDir = __dirname + '/../../players/', playersDir = __dirname + '/../../players/',
serverAddress = utils.serverAddress(); serverAddress = utils.serverAddress();
@ -104,9 +104,9 @@ function revokeScripting ( player ) {
var playerName = '' + player.name; var playerName = '' + player.name;
playerName = playerName.replace(/[^a-zA-Z0-9_\-]/g,''); playerName = playerName.replace(/[^a-zA-Z0-9_\-]/g,'');
var playerDir = new File( playersDir + playerName ); var playerDir = new File( playersDir + playerName );
unwatchFile( playerDir ); unwatchDir( playerDir );
} }
exports.classroomAutoloadTime = 0;
function grantScripting( player ) { function grantScripting( player ) {
console.log('Enabling scripting for player ' + player.name); console.log('Enabling scripting for player ' + player.name);
var playerName = '' + player.name; var playerName = '' + player.name;
@ -117,9 +117,15 @@ function grantScripting( player ) {
var playerContext = {}; var playerContext = {};
autoload( playerContext, playerDir, logger, { cache: false }); autoload( playerContext, playerDir, logger, { cache: false });
global[playerName] = playerContext; global[playerName] = playerContext;
watchDir( playerDir, function( changedDir ){
watchFile( playerDir, function( changedDir ){ var currentTime = new java.util.Date().getTime();
//this check is here because this callback might get called multiple times for the watch interval
//one call for the file change and another for directory change
//(this happens only in Linux because in Windows the folder lastModifiedTime is not changed)
if(currentTime-exports.classroomAutoloadTime>1000) {
autoload(playerContext, playerDir, logger, { cache: false }); autoload(playerContext, playerDir, logger, { cache: false });
}
exports.classroomAutoloadTime = currentTime;
}); });
/* /*