Skip to content
Snippets Groups Projects
y.js 5.72 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kevin Jahns's avatar
    Kevin Jahns committed
    'use strict'
    
    require('./Connector.js')(Y)
    require('./Database.js')(Y)
    require('./Transaction.js')(Y)
    require('./Struct.js')(Y)
    require('./Utils.js')(Y)
    require('./Connectors/Test.js')(Y)
    
    var requiringModules = {}
    
    module.exports = Y
    
    Kevin Jahns's avatar
    Kevin Jahns committed
    Y.requiringModules = requiringModules
    
    
    Y.extend = function (name, value) {
    
      if (value instanceof Y.utils.CustomTypeDefinition) {
    
        Y[name] = value.parseArguments
      } else {
        Y[name] = value
      }
    
      if (requiringModules[name] != null) {
    
        requiringModules[name].resolve()
    
        delete requiringModules[name]
      }
    }
    
    
    Y.requestModules = requestModules
    function requestModules (modules) {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      // determine if this module was compiled for es5 or es6 (y.js vs. y.es6)
      // if Insert.execute is a Function, then it isnt a generator..
      // then load the es5(.js) files..
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      var extention = typeof regeneratorRuntime !== 'undefined' ? '.js' : '.es6'
    
      var promises = []
      for (var i = 0; i < modules.length; i++) {
    
        var module = modules[i].split('(')[0]
        var modulename = 'y-' + module.toLowerCase()
        if (Y[module] == null) {
          if (requiringModules[module] == null) {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
            // module does not exist
            if (typeof window !== 'undefined' && window.Y !== 'undefined') {
              var imported = document.createElement('script')
              imported.src = Y.sourceDir + '/' + modulename + '/' + modulename + extention
              document.head.appendChild(imported)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
              let requireModule = {}
    
              requiringModules[module] = requireModule
    
    Kevin Jahns's avatar
    Kevin Jahns committed
              requireModule.promise = new Promise(function (resolve) {
                requireModule.resolve = resolve
              })
              promises.push(requireModule.promise)
            } else {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
              console.info('YJS: Please do not depend on automatic requiring of modules anymore! Extend modules as follows `require(\'y-modulename\')(Y)`')
    
    Kevin Jahns's avatar
    Kevin Jahns committed
              require(modulename)(Y)
    
          } else {
            promises.push(requiringModules[modules[i]].promise)
    
      return Promise.all(promises)
    }
    
    
    /* ::
    type MemoryOptions = {
      name: 'memory'
    }
    type IndexedDBOptions = {
      name: 'indexeddb',
      namespace: string
    }
    type DbOptions = MemoryOptions | IndexedDBOptions
    
    type WebRTCOptions = {
      name: 'webrtc',
      room: string
    
    type WebsocketsClientOptions = {
      name: 'websockets-client',
      room: string
    }
    type ConnectionOptions = WebRTCOptions | WebsocketsClientOptions
    
    type YOptions = {
      connector: ConnectionOptions,
      db: DbOptions,
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      types: Array<TypeName>,
      sourceDir: string,
      share: {[key: string]: TypeName}
    
    }
    */
    
    function Y (opts/* :YOptions */) /* :Promise<YConfig> */ {
    
      opts.types = opts.types != null ? opts.types : []
      var modules = [opts.db.name, opts.connector.name].concat(opts.types)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      for (var name in opts.share) {
        modules.push(opts.share[name])
      }
    
      Y.sourceDir = opts.sourceDir
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          Y.requestModules(modules).then(function () {
            if (opts == null) reject('An options object is expected! ')
            else if (opts.connector == null) reject('You must specify a connector! (missing connector property)')
            else if (opts.connector.name == null) reject('You must specify connector name! (missing connector.name property)')
            else if (opts.db == null) reject('You must specify a database! (missing db property)')
            else if (opts.connector.name == null) reject('You must specify db name! (missing db.name property)')
            else if (opts.share == null) reject('You must specify a set of shared types!')
            else {
              var yconfig = new YConfig(opts)
              yconfig.db.whenUserIdSet(function () {
                yconfig.init(function () {
                  resolve(yconfig)
                })
    
    Kevin Jahns's avatar
    Kevin Jahns committed
            }
          }).catch(reject)
        }, 0)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      })
    
    Kevin Jahns's avatar
    Kevin Jahns committed
    }
    
    class YConfig {
    
      /* ::
      db: Y.AbstractDatabase;
      connector: Y.AbstractConnector;
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      share: {[key: string]: any};
    
      options: Object;
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      constructor (opts, callback) {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
        this.db = new Y[opts.db.name](this, opts.db)
        this.connector = new Y[opts.connector.name](this, opts.connector)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      }
      init (callback) {
        var opts = this.options
    
    Kevin Jahns's avatar
    Kevin Jahns committed
        var share = {}
        this.share = share
    
    Kevin Jahns's avatar
    Kevin Jahns committed
        this.db.requestTransaction(function * requestTransaction () {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
          // create shared object
          for (var propertyname in opts.share) {
    
            var typeConstructor = opts.share[propertyname].split('(')
            var typeName = typeConstructor.splice(0, 1)
    
            var type = Y[typeName]
            var typedef = type.typeDefinition
            var id = ['_', typedef.struct + '_' + typeName + '_' + propertyname + '_' + typeConstructor]
    
            var args = []
            if (typeConstructor.length === 1) {
              try {
                args = JSON.parse('[' + typeConstructor[0].split(')')[0] + ']')
              } catch (e) {
                throw new Error('Was not able to parse type definition! (share.' + propertyname + ')')
              }
    
              if (type.typeDefinition.parseArguments == null) {
                throw new Error(typeName + ' does not expect arguments!')
              } else {
                args = typedef.parseArguments(args[0])[1]
              }
    
            share[propertyname] = yield* this.store.initType.call(this, id, args)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
          }
    
          this.store.whenTransactionsFinished()
            .then(callback)
    
    Kevin Jahns's avatar
    Kevin Jahns committed
        })
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      }
    
      isConnected () {
        return this.connector.isSynced
      }
      disconnect () {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      reconnect () {
    
    Kevin Jahns's avatar
    Kevin Jahns committed
      destroy () {
    
        if (this.connector.destroy != null) {
          this.connector.destroy()
        } else {
          this.connector.disconnect()
        }
        var self = this
        this.db.requestTransaction(function * () {
          yield* self.db.destroy()
          self.connector = null
          self.db = null
        })
    
    Kevin Jahns's avatar
    Kevin Jahns committed
    
    
    if (typeof window !== 'undefined') {
      window.Y = Y
    }