Skip to content

Commit

Permalink
🎨 ⏱ Cleanup / optimise the server.init() function (#7985)
Browse files Browse the repository at this point in the history
refs #2182

* πŸ”₯ Remove unused options from server init
- this is left over from old code and is now unused

* 🎨 Move knex-migrator check to db health

- Move complex check function into own module
- Call module from server/index.js
- This just improves the readability of server/index.js

* πŸ”₯ Remove old comments

- These comments all make no sense now!

* 🎨 ⏱ Move model init out of promise chain

- Model.init() does not return a promise
- Therefore, we can move it to the top of the init function, outside of the promise change
- This should be a minor optimisation, and again improves readability /clarity of what's happening

* ✨ ⁉️ Move DBHash init / first run to Settings model

- this structure is left over from when we had code we executed on the first run of Ghost
- the implementation used the API to initialise one setting before populateDefaults is called
- this had lots of dependencies - the whole model, API, and permissions structure had to be initialised for it to work
- the new implementation is simpler, it captures the dbHash getting initialised during populateDefaults()
- it also adds an event, so we can do first-run code later if we really want to (or maybe apps can?!)
- perhaps this is hiding behaviour, and there's a nicer way to do it, but populateDefaults seems like a sane place to populate a default setting 😁

* ⏱ Optimise require order so config is first

- the first require to config will cause the files to be read etc
- this ensures that it happens early, and isn't confusingly timed as part of loading a different module

* 🎨 Simplify settings model changes
  • Loading branch information
ErisDS authored and kirrg001 committed Feb 17, 2017
1 parent 9bd50cb commit b00d9fe
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 80 deletions.
40 changes: 40 additions & 0 deletions core/server/data/db/health.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
var KnexMigrator = require('knex-migrator'),
config = require('../../config'),
errors = require('../../errors'),
models = require('../../models');

module.exports.check = function healthCheck() {
var knexMigrator = new KnexMigrator({
knexMigratorFilePath: config.get('paths:appRoot')
});

return knexMigrator.isDatabaseOK()
.catch(function (outerErr) {
if (outerErr.code === 'DB_NOT_INITIALISED') {
throw outerErr;
}

// CASE: migration table does not exist, figure out if database is compatible
return models.Settings.findOne({key: 'databaseVersion', context: {internal: true}})
.then(function (response) {
// CASE: no db version key, database is compatible
if (!response) {
throw outerErr;
}

throw new errors.DatabaseVersionError({
message: 'Your database version is not compatible with Ghost 1.0.0 Alpha (master branch)',
context: 'Want to keep your DB? Use Ghost < 1.0.0 or the "stable" branch. Otherwise please delete your DB and restart Ghost.',
help: 'More information on the Ghost 1.0.0 Alpha at https://support.ghost.org/v1-0-alpha'
});
})
.catch(function (err) {
// CASE: settings table does not exist
if (err.errno === 1 || err.errno === 1146) {
throw outerErr;
}

throw err;
});
});
};
85 changes: 10 additions & 75 deletions core/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,122 +14,57 @@ require('./overrides');

// Module dependencies
var debug = require('debug')('ghost:boot:init'),
uuid = require('uuid'),
Promise = require('bluebird'),
KnexMigrator = require('knex-migrator'),
// Config should be first require, as it triggers the initial load of the config files
config = require('./config'),
Promise = require('bluebird'),
logging = require('./logging'),
errors = require('./errors'),
i18n = require('./i18n'),
api = require('./api'),
models = require('./models'),
permissions = require('./permissions'),
apps = require('./apps'),
auth = require('./auth'),
dbHealth = require('./data/db/health'),
xmlrpc = require('./data/xml/xmlrpc'),
slack = require('./data/slack'),
GhostServer = require('./ghost-server'),
scheduling = require('./scheduling'),
readDirectory = require('./utils/read-directory'),
utils = require('./utils'),
knexMigrator = new KnexMigrator({
knexMigratorFilePath: config.get('paths:appRoot')
}),
dbHash;

function initDbHashAndFirstRun() {
return api.settings.read({key: 'dbHash', context: {internal: true}}).then(function (response) {
var hash = response.settings[0].value,
initHash;

dbHash = hash;

if (dbHash === null) {
initHash = uuid.v4();
return api.settings.edit({settings: [{key: 'dbHash', value: initHash}]}, {context: {internal: true}})
.then(function (response) {
dbHash = response.settings[0].value;
return dbHash;
// Use `then` here to do 'first run' actions
});
}

return dbHash;
});
}
utils = require('./utils');

// ## Initialise Ghost
// Sets up the express server instances, runs init on a bunch of stuff, configures views, helpers, routes and more
// Finally it returns an instance of GhostServer
function init(options) {
function init() {
debug('Init Start...');
options = options || {};

var ghostServer, parentApp;

// ### Initialisation
// The server and its dependencies require a populated config
// It returns a promise that is resolved when the application
// has finished starting up.

// Initialize Internationalization
i18n.init();
debug('I18n done');
models.init();
debug('models done');

return readDirectory(config.getContentPath('apps')).then(function loadThemes(result) {
config.set('paths:availableApps', result);
return api.themes.loadThemes();
}).then(function () {
debug('Themes & apps done');

models.init();
}).then(function () {
return knexMigrator.isDatabaseOK()
.catch(function (outerErr) {
if (outerErr.code === 'DB_NOT_INITIALISED') {
throw outerErr;
}

// CASE: migration table does not exist, figure out if database is compatible
return models.Settings.findOne({key: 'databaseVersion', context: {internal: true}})
.then(function (response) {
// CASE: no db version key, database is compatible
if (!response) {
throw outerErr;
}

throw new errors.DatabaseVersionError({
message: 'Your database version is not compatible with Ghost 1.0.0 Alpha (master branch)',
context: 'Want to keep your DB? Use Ghost < 1.0.0 or the "stable" branch. Otherwise please delete your DB and restart Ghost.',
help: 'More information on the Ghost 1.0.0 Alpha at https://support.ghost.org/v1-0-alpha'
});
})
.catch(function (err) {
// CASE: settings table does not exist
if (err.errno === 1 || err.errno === 1146) {
throw outerErr;
}

throw err;
});
});
return dbHealth.check();
}).then(function () {
debug('DB health check done');
// Populate any missing default settings
return models.Settings.populateDefaults();
}).then(function () {
debug('Models & database done');

// Refresh the API settings cache
return api.settings.updateSettingsCache();
}).then(function () {
debug('Update settings cache done');
// Initialize the permissions actions and objects
// NOTE: Must be done before initDbHashAndFirstRun calls
return permissions.init();
}).then(function () {
debug('Permissions done');
return Promise.join(
// Check for or initialise a dbHash.
initDbHashAndFirstRun(),
// Initialize apps
apps.init(),
// Initialize xmrpc ping
Expand Down
18 changes: 13 additions & 5 deletions core/server/models/settings.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
var Settings,
ghostBookshelf = require('./base'),
Promise = require('bluebird'),
_ = require('lodash'),
uuid = require('uuid'),
ghostBookshelf = require('./base'),
errors = require('../errors'),
Promise = require('bluebird'),
validation = require('../data/validation'),
events = require('../events'),
internalContext = {context: {internal: true}},
i18n = require('../i18n'),
validation = require('../data/validation'),

internalContext = {context: {internal: true}},

defaultSettings;

Expand All @@ -15,12 +17,18 @@ var Settings,
// instead of iterating those categories every time
function parseDefaultSettings() {
var defaultSettingsInCategories = require('../data/schema/').defaultSettings,
defaultSettingsFlattened = {};
defaultSettingsFlattened = {},
dynamicDefault = {
dbHash: uuid.v4()
};

_.each(defaultSettingsInCategories, function each(settings, categoryName) {
_.each(settings, function each(setting, settingName) {
setting.type = categoryName;
setting.key = settingName;
if (dynamicDefault[setting.key]) {
setting.defaultValue = dynamicDefault[setting.key];
}

defaultSettingsFlattened[settingName] = setting;
});
Expand Down

0 comments on commit b00d9fe

Please sign in to comment.