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

locators

v2.0.2

Published

A collection of promise based service discovery 'locators'

Downloads

104

Readme

Locators: a simple service discovery library

Locators is a library to wrap various service discovery mechanisms into a unified promise based format. At it's core, it revolves around the concept of Locations which are represented as a simple object with a host and port property, and Locators, which are a function which return a Promise<Location>. Additionally, a locator implementation may optionally expose a LocatorEmitter instead of a Locator, which is a Locator + EventEmitter.

There are currently three different locators, packaged in this library: SimpleLocator, RequestLocator and ZookeeperLocator. All locators expose a single static method getLocatorFactory which may or may not take a configuration depending on the locator type, and returns a function which can produce Locators that can be resolved in the normal promise flow.

SimpleLocator

SimpleLocator takes no configuration to it's factory creation method. It's locator takes a list of known servers and randomly returns one of the servers.

example

import { SimpleLocator } from 'locators';
const simpleLocator = SimpleLocator.getLocatorFactory();
const locator = simpleLocator({
    resource: "localhost;koalastothemax.com:80",
    defaultPort: 8181
});
locator.then((location) => {
    console.log(location); // either { host: "localhost", port: 8181 } or { host: "koalastothemax.com", port: "80" }
});

RequestLocator

RequestLocator takes no configuration to it's factory creation method. It's locator method takes a remote http/https endpoint that returns a list of servers, and retrieves a list of servers and randomly returns one of the servers, and optionally a data extractor to properly translate the response into a Location. The RequestLocator has a default data extractor which expects the server to respond with an object which has a servers property which is an array of objects which have address and port properties, since it was originally built to work with the exhibitor api call exhibitor/v1/cluster/listdocs.

example

import { RequestLocator } from 'locators'
const requestLocator = RequestLocator.getLocatorFactory();
const locator = requestLocator({
    url: "http://www.test-endpoint.com:8080/list" // returns {"blah": [{"address": "localhost", "port": 8080}, {"address": "localhost", "port": 1234}]}
    dataExtractor: (data) => {
        location = JSON.parse(data).blah[1],
        return {
            host: location.address,
            port: location.port
        }
});
locator.then((location) => { 
    console.log(location); //returns { host: 'localhost', port: 1234 }
})

ZookeeperLocator

ZookeeperLocator uses zookeeper to find other services. For maximum dog-fooding, it's factory creation method takes a Locator for the zookeeper cluster. If you are using exhibitor, you can make use of its list api with the RequestLocator, or if the servers exist in dns, a list of hosts, or ip addresses, then with a SimpleLocator. It is built on top of node-zookeeper-client

example

import { SimpleLocator, ZookeeperLocator } from 'locators';
const simpleLocator = SimpleLocator.getLocatorFactory();
const zookeeperLocator = Zookeeper.getLocatorFactory({
    serverLocator: simpleLocator('localhost:2181')
    path: '/discovery'
    locatorTimeout: 2000
});
const locator = zookeeperLocator('my:service');
locator.then((location) => {
    console.log(location); // returns host and port from zookeeper localhost:2181 
});

The ZookeeperLocator implements the LocatorEmitter pattern

  ZK_LOCATOR_ERROR: "failed to find zookeeper",
  CONNECTED: "connected",
  DISCONNECTED: "disconnected",
  STATE_CHANGE: "state",
  EXPIRED: "expired",
  CONNECTING: "connecting",
  FAILED_TO_GET_CHILDREN: "failed to get child list",
  EMPTY_POOL: "child pool is empty",
  FAILED_TO_GET_CHILD_INFO: "failed to get individual child's info",
  NEW_POOL: "got a new child pool",
  CHILDREN_CHANGED: "child list has changed",
  PATH_FOUND: "zookeeper path is found",
  PATH_NOT_FOUND: "zookeeper path is not found"

The codes emitted are exported as EXCEPTION_CODE from the library, i.e.

import { EXCEPTION_CODE } from 'locators';
import { ZookeeperLocator } from 'locators';

const zookeeperLocator = Zookeeper.getLocatorFactory({
    serverLocator: simpleLocatorFactory()('localhost:2181')
    path: '/discovery'
    locatorTimeout: 2000
});
const locator = zookeeperLocator('my:service');
locator.then((location) => {
    console.log(location); // returns host and port from zookeeper localhost:2181 
});
locator.on(EXCEPTION_CODE.EXPIRED, () => {
    console.log('expired');
});

shorthand syntax

A shorthand syntax exists for using the locators provide by this library for legacy reasons, and can be used as such.

SimpleLocator

example

simpleLocatorFactory = require('locators').simple

locator = simpleLocatorFactory()({
    resource: "localhost;koalastothemax.com:80"
    defaultPort: 8181
})
locator.then((location) -> 
    console.log location #either { host: "localhost", port: 8181 } or { host: "koalastothemax.com", port: "80" }
)

RequestLocator

example

requestLocatorFactory = require('locators').request

locator = requestLocatorFactory()({
    url: "http://www.test-endpoint.com:8080/list" # returns {"blah": [{"address": "localhost", "port": 8080}, {"address": "localhost", "port": 1234}]}
    dataExtractor: (data) ->
        location = JSON.parse(data).blah[1]
        return {
            host: location.address
            port: location.port
        }
})
locator.then((location) -> 
    console.log location #returns { host: 'localhost', port: 1234 }
)

ZookeeperLocator

example

zookeeperLocatorFactory = require('locators').zookeeper

zookeeperLocator = zookeeperLocatorFactory({
    serverLocator: simpleLocatorFactory()('localhost:2181')
    path: '/discovery'
    locatorTimeout: 2000
})
myServiceLocator = zookeeperLocator('my:service')
myServiceLocator.then((location) ->
    console.log location #returns host and port from zookeeper localhost:2181 
)

Development

npm run build to compile.

The ZookeeperLocator test currently require a local installation of zookeeper to run successfully, specified by the zkServerCommandPath variable which is defined near the beginning of the tests.