<commit_before>const Message = require('primea-message')
const BN = require('bn.js')
const PortManager = require('./portManager.js')
const DeleteMessage = require('./deleteMessage')

module.exports = class Kernel {
  /**
   * the Kernel manages the varous message passing functions and provides
   * an interface for the containers to use
   * @param {Object} opts
   * @param {Object} opts.id - the UUID of the Kernel
   * @param {Object} opts.state - the state of the container
   * @param {Object} opts.hypervisor
   * @param {Object} opts.container - the container constuctor and argments
   */
  constructor (opts) {
    this.state = opts.state
    this.hypervisor = opts.hypervisor
    this.id = opts.id
    this.container = new opts.container.Constructor(this, opts.container.args)

    this.ticks = 0
    this.containerState = 'idle'

    // create the port manager
    this.ports = new PortManager(Object.assign({
      kernel: this
    }, opts))
  }

  /**
   * adds a message to this containers message queue
   * @param {string} portName
   * @param {object} message
   */
  queue (portName, message) {
    this.ports.queue(portName, message)
    if (this.containerState !== 'running') {
      this.containerState = 'running'
      return this._runNextMessage()
    }
  }

  initialize (message) {
    this.containerState = 'running'
    return this.run(message, 'initialize')
  }

  // waits for the next message
  async _runNextMessage () {
    // check if the ports are saturated, if so we don't have to wait on the
    // scheduler
    const message = await this.ports.getNextMessage()

    if (message) {
      message.fromPort.messages.shift()
      // if the message we recived had more ticks then we currently have the
      // update it
      if (message._fromTicks > this.ticks) {
        this.ticks = message._fromTicks
        this.hypervisor.scheduler.update(this)
      }
      // run the next message
      return this.run(message)
    } else {
      // if no more messages then shut down
      this.hypervisor.scheduler.done(this.id)
    }
  }

  /**
   * run the kernels code with a given enviroment
   * @param {object} message - the message to run
   * @param {boolean} init - whether or not to run the intialization routine
   * @returns {Promise}
   */
  async run (message, method = 'run') {
    let result

    const responsePort = message.responsePort
    delete message.responsePort

    this.ports.addReceivedPorts(message)
    message._hops++

    if (message.constructor === DeleteMessage) {
      this.ports._delete(message.fromName)
    } else {
      try {
        result = await this.container[method](message) || {}
      } catch (e) {
        result = {
          exception: true,
          exceptionError: e
        }
      }
    }

    if (responsePort) {
      this.send(responsePort, new Message({
        data: result
      }))
      this.ports._unboundPorts.add(responsePort)
    }

    this.ports.clearUnboundedPorts()
    return this._runNextMessage()
  }

  getResponsePort (message) {<commit_msg>implemented main loop<commit_after>const Message = require('primea-message')
const BN = require('bn.js')
const PortManager = require('./portManager.js')
const DeleteMessage = require('./deleteMessage')

module.exports = class Kernel {
  /**
   * the Kernel manages the varous message passing functions and provides
   * an interface for the containers to use
   * @param {Object} opts
   * @param {Object} opts.id - the UUID of the Kernel
   * @param {Object} opts.state - the state of the container
   * @param {Object} opts.hypervisor
   * @param {Object} opts.container - the container constuctor and argments
   */
  constructor (opts) {
    this.state = opts.state
    this.hypervisor = opts.hypervisor
    this.id = opts.id
    this.container = new opts.container.Constructor(this, opts.container.args)

    this.ticks = 0
    this.containerState = 'idle'

    // create the port manager
    this.ports = new PortManager(Object.assign({
      kernel: this
    }, opts))
  }

  /**
   * adds a message to this containers message queue
   * @param {string} portName
   * @param {object} message
   */
  queue (portName, message) {
    this.ports.queue(portName, message)
    return this._startMessageLoop()
  }

  async initialize (message) {
    await this.run(message, 'initialize')
    return this._startMessageLoop()
  }

  // waits for the next message
  async _startMessageLoop () {
    // this ensure we only every have one loop running at a time
    if (this.containerState !== 'running') {
      this.containerState = 'running'

      while (1) {
        let message = await this.ports.getNextMessage()
        if (!message) break

        message.fromPort.messages.shift()
          // if the message we recived had more ticks then we currently have the
          // update it
        if (message._fromTicks > this.ticks) {
          this.ticks = message._fromTicks
          this.hypervisor.scheduler.update(this)
        }
        // run the next message
        await this.run(message)
      }
      // no more messages; shut down
      this.hypervisor.scheduler.done(this.id)
    }
  }

  /**
   * run the kernels code with a given enviroment
   * @param {object} message - the message to run
   * @param {boolean} init - whether or not to run the intialization routine
   * @returns {Promise}
   */
  async run (message, method = 'run') {
    let result

    const responsePort = message.responsePort
    delete message.responsePort

    this.ports.addReceivedPorts(message)
    message._hops++

    if (message.constructor === DeleteMessage) {
      this.ports._delete(message.fromName)
    } else {
      try {
        result = await this.container[method](message) || {}
      } catch (e) {
        result = {
          exception: true,
          exceptionError: e
        }
      }
    }

    if (responsePort) {
      this.send(responsePort, new Message({
        data: result
      }))
    }

    this.ports.clearUnboundedPorts()
  }

  getResponsePort (message) {
{'fraction_non_alphanumeric': 0.10610826022181757, 'fraction_numerical': 0.0004966065220989903, 'mean_word_length': 2.541617819460727, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4058224', 'n_tokens_mistral': 1774, 'n_tokens_neox': 1729, 'n_words': 512}