aboutsummaryrefslogblamecommitdiffhomepage
path: root/scripts/mongo-to-postgre.js
blob: 6cd1ef3b4437fc8cdfc9b155b866055fbd62ae99 (plain) (tree)






























































































































                                                                                                         
                                                 



















                                                                                    
                                                 




















































































                                                                                    
                                                  


                     
#!/usr/bin/env node

'use strict'

// TODO: document this script

const program = require('commander')
const eachSeries = require('async/eachSeries')
const series = require('async/series')
const waterfall = require('async/waterfall')
const fs = require('fs')
const path = require('path')
const MongoClient = require('mongodb').MongoClient

const constants = require('../server/initializers/constants')

program
  .option('-mh, --mongo-host [host]', 'MongoDB host', 'localhost')
  .option('-mp, --mongo-port [weight]', 'MongoDB port', '27017')
  .option('-md, --mongo-database [dbname]', 'MongoDB database')
  .parse(process.argv)

if (!program.mongoDatabase) {
  console.error('The mongodb database is mandatory.')
  process.exit(-1)
}

const mongoUrl = 'mongodb://' + program.mongoHost + ':' + program.mongoPort + '/' + program.mongoDatabase
const dbSequelize = require('../server/initializers/database')

console.log('Connecting to ' + mongoUrl)
MongoClient.connect(mongoUrl, function (err, dbMongo) {
  if (err) throw err

  console.log('Connected to ' + mongoUrl)

  const videoMongo = dbMongo.collection('videos')
  const userMongo = dbMongo.collection('users')
  const podMongo = dbMongo.collection('pods')

  podMongo.count(function (err, podsLength) {
    if (err) throw err

    if (podsLength > 0) {
      console.error('You need to quit friends first.')
      process.exit(-1)
    }

    console.log('Connecting to ' + dbSequelize.sequelize.config.database)
    dbSequelize.init(true, function (err) {
      if (err) throw err

      console.log('Connected to SQL database %s.', dbSequelize.sequelize.config.database)

      series([
        function (next) {
          dbSequelize.sequelize.sync({ force: true }).asCallback(next)
        },

        function (next) {
          migrateVideos(videoMongo, dbSequelize, next)
        },

        function (next) {
          migrateUsers(userMongo, dbSequelize, next)
        }
      ], function (err) {
        if (err) console.error(err)

        process.exit(0)
      })
    })
  })
})

// ---------------------------------------------------------------------------

function migrateUsers (userMongo, dbSequelize, callback) {
  userMongo.find().toArray(function (err, mongoUsers) {
    if (err) return callback(err)

    eachSeries(mongoUsers, function (mongoUser, callbackEach) {
      console.log('Migrating user %s', mongoUser.username)

      const userData = {
        username: mongoUser.username,
        password: mongoUser.password,
        role: mongoUser.role
      }
      const options = {
        hooks: false
      }

      dbSequelize.User.create(userData, options).asCallback(callbackEach)
    }, callback)
  })
}

function migrateVideos (videoMongo, dbSequelize, finalCallback) {
  videoMongo.find().toArray(function (err, mongoVideos) {
    if (err) return finalCallback(err)

    eachSeries(mongoVideos, function (mongoVideo, callbackEach) {
      console.log('Migrating video %s.', mongoVideo.name)

      waterfall([

        function startTransaction (callback) {
          dbSequelize.sequelize.transaction().asCallback(function (err, t) {
            return callback(err, t)
          })
        },

        function findOrCreatePod (t, callback) {
          if (mongoVideo.remoteId === null) return callback(null, t, null)

          const query = {
            where: {
              host: mongoVideo.podHost
            },
            defaults: {
              host: mongoVideo.podHost
            },
            transaction: t
          }

          dbSequelize.Pod.findOrCreate(query).asCallback(function (err, result) {
            // [ instance, wasCreated ]
            const res = result ? result[0] : null
            return callback(err, t, res)
          })
        },

        function findOrCreateAuthor (t, pod, callback) {
          const podId = pod ? pod.id : null
          const username = mongoVideo.author

          const query = {
            where: {
              podId,
              name: username
            },
            defaults: {
              podId,
              name: username
            },
            transaction: t
          }

          dbSequelize.Author.findOrCreate(query).asCallback(function (err, result) {
            // [ instance, wasCreated ]
            const res = result ? result[0] : null
            return callback(err, t, res)
          })
        },

        function findOrCreateTags (t, author, callback) {
          const tags = mongoVideo.tags
          const tagInstances = []

          eachSeries(tags, function (tag, callbackEach) {
            const query = {
              where: {
                name: tag
              },
              defaults: {
                name: tag
              },
              transaction: t
            }

            dbSequelize.Tag.findOrCreate(query).asCallback(function (err, res) {
              if (err) return callbackEach(err)

              // res = [ tag, isCreated ]
              const tag = res[0]
              tagInstances.push(tag)
              return callbackEach()
            })
          }, function (err) {
            return callback(err, t, author, tagInstances)
          })
        },

        function createVideoObject (t, author, tagInstances, callback) {
          const videoData = {
            name: mongoVideo.name,
            remoteId: mongoVideo.remoteId,
            extname: mongoVideo.extname,
            infoHash: mongoVideo.magnet.infoHash,
            description: mongoVideo.description,
            authorId: author.id,
            duration: mongoVideo.duration,
            createdAt: mongoVideo.createdDate
          }

          const video = dbSequelize.Video.build(videoData)

          return callback(null, t, tagInstances, video)
        },

        function moveVideoFile (t, tagInstances, video, callback) {
          const basePath = constants.CONFIG.STORAGE.VIDEOS_DIR
          const src = path.join(basePath, mongoVideo._id.toString()) + video.extname
          const dst = path.join(basePath, video.id) + video.extname
          fs.rename(src, dst, function (err) {
            if (err) return callback(err)

            return callback(null, t, tagInstances, video)
          })
        },

        function insertVideoIntoDB (t, tagInstances, video, callback) {
          const options = {
            transaction: t
          }

          video.save(options).asCallback(function (err, videoCreated) {
            return callback(err, t, tagInstances, videoCreated)
          })
        },

        function associateTagsToVideo (t, tagInstances, video, callback) {
          const options = { transaction: t }

          video.setTags(tagInstances, options).asCallback(function (err) {
            return callback(err, t)
          })
        }

      ], function (err, t) {
        if (err) {
          // Abort transaction?
          if (t) t.rollback()

          return callbackEach(err)
        }

        // Commit transaction
        return t.commit().asCallback(callbackEach)
      })
    }, finalCallback)
  })
}