npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

haraka-results

v2.2.4

Published

Haraka results store for connections and transactions

Downloads

6,437

Readme

haraka-results

Build Status Code Coverage Code Climate NPM

Add, log, retrieve, and share the results of plugin tests.

Synopsis

Results is a structured way of storing results from plugins across a session, allowing those results to be retrieved later or by other plugins.

Results objects are present on every Haraka connection and transaction. When in a SMTP transaction, results from both are applicable to that transaction.

Usage

Use results in your plugins like so:

exports.my_first_hook = function (next, connection) {

    // run a test
    ......

    // store the results
    connection.results.add(this, {pass: 'my great test' })

    // run another test
    .....

    // store the results
    connection.results.add(this, {fail: 'gotcha!', msg: 'show this'})
}

Store the results in the transaction (vs connection):

   connection.transaction.results.add(this, {...});`

Config options

Each plugin can have custom settings in results.ini to control results logging. There are three options available: hide, order, and debug.

  • hide - a comma separated list of results to hide from the output
  • order - a comman separated list, specifing the order of items in the output
  • debug - log debug messages every time results are called
; put this in config/results.ini
[plugin_name]
hide=skip
order=msg,pass,fail
debug=0

Results Functions

add

Store information. Most calls to results will append data to the lists in the connection. The following lists are available:

pass  - names of tests that passed
fail  - names of tests that failed
skip  - names of tests that were skipped (with a why, if you wish)
err   - error messages encountered during processing
msg   - arbitratry messages

human - a custom summary to return (bypass collate)
emit  - log an INFO summary

When err results are received, a logerror is automatically emitted, saving the need to specify {emit: true} with the request.

Examples:

    const results = connection.results
    results.add(this, {pass: 'null_sender'})
    results.add(this, {fail: 'single_recipient'})
    results.add(this, {skip: 'valid_bounce'}
    results.add(this, {err: 'timed out looking in couch cushions'})
    results.add(this, {msg: 'I found a nickel!', emit: true})

In addition to appending values to the predefined lists, arbitrary results can be stored in the cache:

results.add(this, { my_result: 'anything I want' })

When arbirary values are stored, they are listed first in the log output. Their display can be suppressed with the hide option in results.ini.

incr

Increment counters. The argument to incr is an object with counter names and increment values. Examples:

results.incr(this, { unrecognized_commands: 1 })

results.incr(this, { karma: -1 })
results.incr(this, { karma: 2 })

push

Append items onto arrays. The argument to push is an object with array names and the new value to be appended to the array. Examples:

results.push(this, { dns_recs: 'name1' })
results.push(this, { dns_recs: 'name2' })

collate

const summary = results.collate(this)

Formats the contents of the result cache and returns them. This function is called internally by add() after each update.

get

Retrieve the stored results as an object. The only argument is the name of the plugin whose results are desired.

    const geoip = results.get('geoip')
    if (geoip && geoip.distance && geoip.distance > 2000) {
        ....
    }

Keep in mind that plugins also store results in the transaction. Example:

    const sa = connection.transaction.results.get('spamassassin')
    if (sa && sa.score > 5) {
        ....
    }

has

Check result contents for string or pattern matches.

Syntax:

results.has('plugin_name', 'result_name', 'search_term')
  • result_name: the name of an array or string in the result object
  • search_term: a string or RegExp object

More Examples

Store Results:

results.add(this, { pass: 'some_test' })
results.add(this, { pass: 'some_test(with reason)' })

Retrieve exact match with get:

if (results.get('plugin_name').pass.indexOf('some_test') !== -1) {
  // some_test passed (1x)
}

Retrieve a string match with has

if (results.has('plugin_name', 'pass', 'some_test')) {
  // some_test passed (1x)
}

The syntax for using has is a little more pleasant.

Both options require one to check for each reason which is unpleasant when and all we really want to know is if some_test passed or not.

Retrieve a matching pattern:

if (results.has('plugin_name', 'pass', /^some_test/)) {
  // some_test passed (2x)
}

Private Results

To store structured data in results that are hidden from the human and human_html output, prefix the name of the key with an underscore.

Example:

results.add(this, { _hidden: 'some data' })

Redis Pub/Sub

If a redis client is found on server.notes.redis, then new results are JSON encoded and published to Redis on the channel named result-${UUID}. This feature can be disabled by setting [main]redis_publish=false in results.ini. Plugins can recieve the events by psubscribing (pattern subscribe) to the channel named result-${UUID}* where ${UUID} is the connection UUID.

This is from the karma plugin subscribing on the connect_init hook:

exports.register = function (next, server) {
  this.inherits('redis')

  register_hook('connect_init', 'redis_subscribe')
  register_hook('disconnect', 'redis_unsubscribe')
}

exports.redis_subscribe = function (next, connection) {
  this.redis_subscribe(connection, function () {
    connection.notes.redis.on('pmessage', (pattern, channel, message) => {
      // do stuff with messages that look like this
      // {"plugin":"karma","result":{"fail":"spamassassin.hits"}}
      // {"plugin":"geoip","result":{"country":"CN"}}
    })
    next()
  })
}
exports.redis_unsubscribe = function (next, connection) {
  this.redis_unsubscribe(connection)
}