/** * @license * Copyright 2015 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ 'use strict'; var clone = require('lodash.clone'); var grpc = require('./grpc_extension'); /** * Class for storing metadata. Keys are normalized to lowercase ASCII. * @memberof grpc * @constructor * @example * var metadata = new metadata_module.Metadata(); * metadata.set('key1', 'value1'); * metadata.add('key1', 'value2'); * metadata.get('key1') // returns ['value1', 'value2'] */ function Metadata() { this._internal_repr = {}; } function normalizeKey(key) { key = key.toLowerCase(); if (grpc.metadataKeyIsLegal(key)) { return key; } else { throw new Error('Metadata key"' + key + '" contains illegal characters'); } } function validate(key, value) { if (grpc.metadataKeyIsBinary(key)) { if (!(value instanceof Buffer)) { throw new Error('keys that end with \'-bin\' must have Buffer values'); } } else { if (typeof value !== 'string') { throw new Error( 'keys that don\'t end with \'-bin\' must have String values'); } if (!grpc.metadataNonbinValueIsLegal(value)) { throw new Error('Metadata string value "' + value + '" contains illegal characters'); } } } /** * Sets the given value for the given key, replacing any other values associated * with that key. Normalizes the key. * @param {String} key The key to set * @param {String|Buffer} value The value to set. Must be a buffer if and only * if the normalized key ends with '-bin' */ Metadata.prototype.set = function(key, value) { key = normalizeKey(key); validate(key, value); this._internal_repr[key] = [value]; }; /** * Adds the given value for the given key. Normalizes the key. * @param {String} key The key to add to. * @param {String|Buffer} value The value to add. Must be a buffer if and only * if the normalized key ends with '-bin' */ Metadata.prototype.add = function(key, value) { key = normalizeKey(key); validate(key, value); if (!this._internal_repr[key]) { this._internal_repr[key] = []; } this._internal_repr[key].push(value); }; /** * Remove the given key and any associated values. Normalizes the key. * @param {String} key The key to remove */ Metadata.prototype.remove = function(key) { key = normalizeKey(key); if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { delete this._internal_repr[key]; } }; /** * Gets a list of all values associated with the key. Normalizes the key. * @param {String} key The key to get * @return {Array.} The values associated with that key */ Metadata.prototype.get = function(key) { key = normalizeKey(key); if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { return this._internal_repr[key]; } else { return []; } }; /** * Get a map of each key to a single associated value. This reflects the most * common way that people will want to see metadata. * @return {Object.} A key/value mapping of the metadata */ Metadata.prototype.getMap = function() { var result = {}; Object.keys(this._internal_repr).forEach(key => { const values = this._internal_repr[key]; if(values.length > 0) { result[key] = values[0]; } }); return result; }; /** * Clone the metadata object. * @return {grpc.Metadata} The new cloned object */ Metadata.prototype.clone = function() { var copy = new Metadata(); Object.keys(this._internal_repr).forEach(key => { const value = this._internal_repr[key]; copy._internal_repr[key] = clone(value); }); return copy; }; /** * Gets the metadata in the format used by interal code. Intended for internal * use only. API stability is not guaranteed. * @private * @return {Object.>} The metadata */ Metadata.prototype._getCoreRepresentation = function() { return this._internal_repr; }; /** * Creates a Metadata object from a metadata map in the internal format. * Intended for internal use only. API stability is not guaranteed. * @private * @param {Object.>} The metadata * @return {Metadata} The new Metadata object */ Metadata._fromCoreRepresentation = function(metadata) { var newMetadata = new Metadata(); if (metadata) { Object.keys(metadata).forEach(key => { const value = metadata[key]; newMetadata._internal_repr[key] = clone(value); }); } return newMetadata; }; module.exports = Metadata;