<commit_before>/*
 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
 *
 * A brief overview of this source file: what is its purpose.
 */


var EventEmitter = require('events').EventEmitter;
var sprintf = require('sprintf').sprintf;
var assert = require('assert');
var restify = require('restify');
var util = require('util');

var errors = require('../errors');
var common = require('./../common');
var moray = require('moray');

var PARAM_FILTER = '(%s=%s)';


// Only indexed columns can be searched
var SEARCHABLE_FIELDS = [
    'uuid',
    'owner_uuid',
    'image_uuid',
    'billing_id',
    'server_uuid',
    'package_name',
    'package_version',
    'brand',
    'state',
    'alias',
    'max_physical_memory',
    'ram',
    'create_timestamp'
];

/*
 * Basically the VMs table
 */
var VMS_BUCKET_NAME = 'vmapi_vms';
var VMS_BUCKET = {
    index: {
        uuid: { type: 'string', unique: true},
        owner_uuid: { type: 'string' },
        image_uuid: { type: 'string' },
        billing_id: { type: 'string' },
        server_uuid: { type: 'string' },
        package_name: { type: 'string' },
        package_version: { type: 'string' },
        tags: { type: 'string' },
        brand: { type: 'string' },
        state: { type: 'string' },
        alias: { type: 'string' },
        max_physical_memory: { type: 'number' },
        create_timestamp: { type: 'number' }
    }
};



/*
 * Moray constructor
 */
function Moray(options) {
    EventEmitter.call(this);
    this.log = options.log;
    this.options = options;
    this.connected = false;
    this.reconnecting = false;
}

util.inherits(Moray, EventEmitter);



/*
 * Attempts to connect to moray, retrying until connection is established. After
 * connection is established buckets get initialized
 */
Moray.prototype.connect = function (cb) {
    var self = this;
    this.log.debug('Connecting to moray...');

    attemptConnect.call(this, function () {
        self._setupBuckets(function (err) {
            if (!err) {
                self.log.info('Buckets have been loaded');
            }

            // When reconnecting we're not part of async.series
            if (!self.reconnecting) {
                return cb(err);
            }
        });
    });
};



/*
 * Called by Moray.connect. This function will use default retry options for
 * connecting to moray. When connection is ready it will call the callback so
 * connect() can proceed to initialize buckets
 */
function attemptConnect(cb) {
    var log = this.log;
    var retry = this.options.retry || {};
    var self = this;

    var connection = this.connection = moray.createClient({
        connectTimeout: this.options.connectTimeout || 200,
        log: this.log,
        host: this.options.host,
        port: this.options.port,
        reconnect: true,
        retry: (this.options.retry === false ? false : {
            retries: Infinity,
            minTimeout: retry.minTimeout || 1000,
            maxTimeout: retry.maxTimeout || 16000
        })
    });

    connection.on('connect', onConnect);
    connection.on('connectAttempt', onConnectAttempt);

    connection.on('close', function () {
        self.connected = false;
        self.reconnecting = true;
        log.error('moray: closed');
    });

    connection.on('error', function (err) {
        self.connected = false;
        log.warn(err, 'moray: error (reconnecting)');
        self.connect(cb);
    });

    function onConnect() {
        log.info({ moray: connection.toString() }, 'moray: connected');
        self.connected = true;
        cb();
    }

    function onConnectAttempt(number, delay) {
        var level;
        if (number === 0) {
            level = 'info';
        } else if (number < 5) {
            level = 'warn';
        } else {
            level = 'error';
        }
        log[level]({
            attempt: number,
            delay: delay
        }, 'moray: connection attempted');
    }
}



/*
 * Pings Moray by calling its ping method
 */
Moray.prototype.ping = function (callback) {
    // Default ping timeout is 1 second
    return this.connection.ping({}, callback);
};



/*
 * Gets a VM object from moray. uuid is required param and owner_uuid is
 * optional
 */
Moray.prototype.getVm = function (params, cb) {
    var uuid = params.uuid;
    var owner = params.owner_uuid;
    var filter = '';
    var error;

    if (!common.validUUID(uuid)) {
        error = [ errors.invalidUuidErr('uuid') ];
        return cb(new errors.ValidationFailedError('Invalid Parameters',
            error));
    }

    filter += sprintf(PARAM_FILTER, 'uuid', uuid);

    if (owner) {
        if (!common.validUUID(owner)) {<commit_msg>ZAPI-259: /ping is broken<commit_after>/*
 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
 *
 * A brief overview of this source file: what is its purpose.
 */


var EventEmitter = require('events').EventEmitter;
var sprintf = require('sprintf').sprintf;
var assert = require('assert');
var restify = require('restify');
var util = require('util');

var errors = require('../errors');
var common = require('./../common');
var moray = require('moray');

var PARAM_FILTER = '(%s=%s)';


// Only indexed columns can be searched
var SEARCHABLE_FIELDS = [
    'uuid',
    'owner_uuid',
    'image_uuid',
    'billing_id',
    'server_uuid',
    'package_name',
    'package_version',
    'brand',
    'state',
    'alias',
    'max_physical_memory',
    'ram',
    'create_timestamp'
];

/*
 * Basically the VMs table
 */
var VMS_BUCKET_NAME = 'vmapi_vms';
var VMS_BUCKET = {
    index: {
        uuid: { type: 'string', unique: true},
        owner_uuid: { type: 'string' },
        image_uuid: { type: 'string' },
        billing_id: { type: 'string' },
        server_uuid: { type: 'string' },
        package_name: { type: 'string' },
        package_version: { type: 'string' },
        tags: { type: 'string' },
        brand: { type: 'string' },
        state: { type: 'string' },
        alias: { type: 'string' },
        max_physical_memory: { type: 'number' },
        create_timestamp: { type: 'number' }
    }
};



/*
 * Moray constructor
 */
function Moray(options) {
    EventEmitter.call(this);
    this.log = options.log;
    this.options = options;
    this.connected = false;
    this.reconnecting = false;
}

util.inherits(Moray, EventEmitter);



/*
 * Attempts to connect to moray, retrying until connection is established. After
 * connection is established buckets get initialized
 */
Moray.prototype.connect = function (cb) {
    var self = this;
    this.log.debug('Connecting to moray...');

    attemptConnect.call(this, function () {
        self._setupBuckets(function (err) {
            if (!err) {
                self.log.info('Buckets have been loaded');
            }

            // When reconnecting we're not part of async.series
            if (!self.reconnecting) {
                return cb(err);
            }
        });
    });
};



/*
 * Called by Moray.connect. This function will use default retry options for
 * connecting to moray. When connection is ready it will call the callback so
 * connect() can proceed to initialize buckets
 */
function attemptConnect(cb) {
    var log = this.log;
    var retry = this.options.retry || {};
    var self = this;

    var connection = this.connection = moray.createClient({
        connectTimeout: this.options.connectTimeout || 200,
        log: this.log,
        host: this.options.host,
        port: this.options.port,
        reconnect: true,
        retry: (this.options.retry === false ? false : {
            retries: Infinity,
            minTimeout: retry.minTimeout || 1000,
            maxTimeout: retry.maxTimeout || 16000
        })
    });

    connection.on('connect', onConnect);
    connection.on('connectAttempt', onConnectAttempt);

    connection.on('close', function () {
        self.connected = false;
        self.reconnecting = true;
        log.error('moray: closed');
    });

    connection.on('error', function (err) {
        self.connected = false;
        log.warn(err, 'moray: error (reconnecting)');
        self.connect(cb);
    });

    function onConnect() {
        log.info({ moray: connection.toString() }, 'moray: connected');
        self.connected = true;
        cb();
    }

    function onConnectAttempt(number, delay) {
        var level;
        if (number === 0) {
            level = 'info';
        } else if (number < 5) {
            level = 'warn';
        } else {
            level = 'error';
        }
        log[level]({
            attempt: number,
            delay: delay
        }, 'moray: connection attempted');
    }
}



/*
 * Pings Moray by calling its ping method
 */
Moray.prototype.ping = function (callback) {
    // Default ping timeout is 1 second
    return this.connection.ping({ log: this.log }, callback);
};



/*
 * Gets a VM object from moray. uuid is required param and owner_uuid is
 * optional
 */
Moray.prototype.getVm = function (params, cb) {
    var uuid = params.uuid;
    var owner = params.owner_uuid;
    var filter = '';
    var error;

    if (!common.validUUID(uuid)) {
        error = [ errors.invalidUuidErr('uuid') ];
        return cb(new errors.ValidationFailedError('Invalid Parameters',
            error));
    }

    filter += sprintf(PARAM_FILTER, 'uuid', uuid);

    if (owner) {
        if (!common.validUUID(owner)) {
{'fraction_non_alphanumeric': 0.1379420197515132, 'fraction_numerical': 0.004353828183073166, 'mean_word_length': 2.3516014234875446, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '2437482', 'n_tokens_mistral': 2874, 'n_tokens_neox': 2783, 'n_words': 749}