diff --git a/admin/static/js/app.js b/admin/static/js/app.js
index 9ecac1a7..64baef5f 100644
--- a/admin/static/js/app.js
+++ b/admin/static/js/app.js
@@ -421,6 +421,7 @@ angular.module("FICApp")
$rootScope.settings.start = new Date(response.start);
$rootScope.settings.end = new Date(response.end);
$rootScope.settings.generation = new Date(response.generation);
+ $rootScope.settings.activateTime = new Date(response.activateTime);
})
$scope.configro = ROSettings.get();
$scope.duration = 240;
@@ -430,11 +431,13 @@ angular.module("FICApp")
var nStart = this.config.start;
var nEnd = this.config.end;
var nGen = this.config.generation;
+ var aTime = this.config.activateTime;
this.config.$update(function() {
$rootScope.newBox('success', msg);
$rootScope.settings.start = new Date(nStart);
$rootScope.settings.end = new Date(nEnd);
$rootScope.settings.generation = new Date(nGen);
+ $rootScope.settings.activateTime = new Date(aTime);
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when saving settings:', response.data.errmsg);
});
@@ -456,6 +459,11 @@ angular.module("FICApp")
$scope.saveSettings();
});
}
+ $scope.updActivateTime = function() {
+ var ts = Date.now() - Date.now() % 60000;
+ var d = new Date(ts + 120000);
+ this.config.activateTime = d.toISOString();
+ }
$scope.reset = function(type) {
if (confirm("Êtes-vous sûr ?")) {
$http.post("/api/reset", {"type": type}).then(function(time) {
diff --git a/admin/static/views/settings.html b/admin/static/views/settings.html
index 815e6ea5..4fa80130 100644
--- a/admin/static/views/settings.html
+++ b/admin/static/views/settings.html
@@ -83,6 +83,14 @@
+
diff --git a/frontend/static/js/challenge.js b/frontend/static/js/challenge.js
index ffd1777b..fd38a6c4 100644
--- a/frontend/static/js/challenge.js
+++ b/frontend/static/js/challenge.js
@@ -84,11 +84,15 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
refreshSettingsInterval = $interval(refreshSettings, Math.floor(Math.random() * 24000) + 32000);
$http.get("/settings.json").then(function(response) {
- $rootScope.recvTime(response);
+ var time = $rootScope.recvTime(response);
response.data.start = new Date(response.data.start);
response.data.end = new Date(response.data.end);
response.data.generation = new Date(response.data.generation);
- $rootScope.settings = response.data;
+ response.data.activateTime = new Date(response.data.activateTime);
+ if (response.data.activateTime <= new Date(Date.now() + (time.cu - time.he)))
+ $rootScope.settings = response.data;
+ else
+ $rootScope.settings.activateTime = response.data.activateTime;
});
}
@@ -210,12 +214,15 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
actMenu();
}
- $rootScope.refresh = function(justMy) {
+ $rootScope.refresh = function(justMy, justSettings) {
if (!justMy) {
refreshSettings();
refreshThemes();
$rootScope.refreshTeams();
}
+ else if (justSettings) {
+ refreshSettings();
+ }
refreshMy();
}
$rootScope.refresh();
diff --git a/frontend/static/js/common.js b/frontend/static/js/common.js
index 4f6a457d..87e9c371 100644
--- a/frontend/static/js/common.js
+++ b/frontend/static/js/common.js
@@ -144,15 +144,16 @@ angular.module("FICApp")
"he": (new Date()).getTime(),
};
sessionStorage.userService = angular.toJson(time);
+ return time;
}
function updTime() {
if (time && $rootScope.settings) {
var srv_cur = new Date(Date.now() + (time.cu - time.he));
- // Refresh on start time reached
- if (Math.floor($rootScope.settings.start / 1000) == Math.floor(srv_cur / 1000))
- $rootScope.refresh(true);
+ // Refresh on start/activate time reached
+ if (Math.floor($rootScope.settings.start / 1000) == Math.floor(srv_cur / 1000) ||Math.floor($rootScope.settings.activateTime / 1000) == Math.floor(srv_cur / 1000))
+ $rootScope.refresh(true, true);
var remain = 0;
if ($rootScope.settings.start == 0) {
diff --git a/settings/settings.go b/settings/settings.go
index b29d5add..d45a46aa 100644
--- a/settings/settings.go
+++ b/settings/settings.go
@@ -35,6 +35,8 @@ type FICSettings struct {
End time.Time `json:"end"`
// Generation is a value used to regenerate static files.
Generation time.Time `json:"generation"`
+ // ActivateTime is the time when the current file should be proceed.
+ ActivateTime time.Time `json:"activateTime"`
// FirstBlood is the coefficient applied to each first team who solve a challenge.
FirstBlood float64 `json:"firstBlood"`
@@ -129,11 +131,7 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
go func(){
for range c {
log.Println("SIGHUP received, reloading settings...")
- if config, err := ReadSettings(settingsPath); err != nil {
- log.Println("ERROR: Unable to read challenge settings:", err)
- } else {
- reload(config)
- }
+ go tryReload(settingsPath, reload)
}
}()
@@ -152,11 +150,7 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
case ev := <-watcher.Events:
if path.Base(ev.Name) == SettingsFile && ev.Op & fsnotify.Write == fsnotify.Write {
log.Println("Settings file changes, reloading it!")
- if config, err := ReadSettings(settingsPath); err != nil {
- log.Println("ERROR: Unable to read challenge settings:", err)
- } else {
- reload(config)
- }
+ go tryReload(settingsPath, reload)
}
case err := <-watcher.Errors:
log.Println("watcher error:", err)
@@ -165,3 +159,16 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
}()
}
}
+
+func tryReload(settingsPath string, reload func (FICSettings)) {
+ if config, err := ReadSettings(settingsPath); err != nil {
+ log.Println("ERROR: Unable to read challenge settings:", err)
+ } else if time.Until(config.ActivateTime) > 0 {
+ log.Println("Configuration reloading postponed, activating at:", config.ActivateTime)
+ time.Sleep(time.Until(config.ActivateTime))
+ log.Println("Time to activate configuration...")
+ tryReload(settingsPath, reload)
+ } else {
+ reload(config)
+ }
+}