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

jayeson.lib.streamfinder

v1.0.0

Published

Javascript implementation of Streamfinder client

Downloads

2

Readme

Streamfinder Library

The streamfinder library wraps around the HTTP calls of the streamfinder server and provides an API to the service. The library consists of 2 independent clients. User can choose to install the java client or the js client that runs on the browser.

Java Client

The java streamfinder module comes with a Discoverer, Advertiser, SessionFactory (for authentication and ticketing). An additional user permissions module can perform database queries for a list of known users and resolve stream permissions.

Installation

For java clients, include the following file in your build.gradle:

projDependency ':jayeson.lib.streamfinder', 'jayeson:jayeson.lib.streamfinder:1.0.0', false

Clients using only discover/advertise/authentication services will want to install the streamfinder module via Guice

import jayeson.lib.streamfinder.StreamfinderModule;
public class MyModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new StreamfinderModule());
    }
}

Installing the users permission module requires a Guice setup...

import jayeson.lib.streamfinder.UserPermissionModule;
    ...
    // In the overwritten AbstractModule.configure
    install(new UserPermissionModule());

...and a copy of conf-sample/ to the conf/ folder of your executable project. Be sure to include the correct database URL/username/password in persistence.xml.

SessionFactory and Authentication

The SessionFactory is a singleton object that is used for authentication and ticketing purposes. After installing the streamfinder module with Guice, users can obtain a sessionFactory by injection.

@Inject
public void setSessionFactory(SessionFactory factory) {
    // Store factory reference
}

At any time, SessionFactory stores a single session for a given user. This session is the same session that will be shared between discoverer and advertiser. We can access a session directly as such:

CompletableFuture<SessionToken> f = factory.getSession("username", "password", "http://streamfinder");

This call will login the user and create a session if none exist. If the user is already authenticated on the current application, the existing session will be retrieved and no additional HTTP calls will be made to the streamfinder server.

After the future completes and a SessionToken is available, we can access the sessionData.

SessionToken token = f.get();
String sessionData = token.getCookie();

This session data is a cookie header. It can be forwarded when manually making calls to protected resources which require user authentication.

When authentication fails due to a wrong username or password, users can check the session token for an error message.

if (!token.isAuthenticated()) {
    System.out.println(token.getError());
}

Network errors that occur while creating a session are handled differently. These errors are retrieved from the future when it completes exceptionally. The session token will not be available when a network error occurs.

f.exceptionally(error -> {
    try {
        throw error.getCause();
    } catch (UnknownHostException err) {
        System.out.println("Unable to resolve address");
    } catch (ConnectionException err) {
        System.out.println("Cannot reach streamfinder server");
    }
});

Users are advised not to access session tokens directly if possible. When using services such as discover/advertise, the tokens are internally managed. These session tokens are kept alive and automatically recreated if they expire. However, When accessing session tokens directly, users are exposed to these details and will have to manually maintain them. These tokens are said to be unmanaged.

Valid session tokens that are retrieved will be cached in the factory for later use. These tokens need to be regularly maintained by making calls with the token. However, if the same user session is shared by a discoverer or advertiser, the session does not have to be renewed as these services will make calls to keep the session alive.

If an unmanaged session token were to expire, users have to invalidate this token to prevent it from being resued in subsequent calls.

factory.invalidate("username", "password", "http://streamfinder");

After the session for the user is invalidated, subsequent calls to getSession() will return a new session.

Retrieving and Updating of Tickets

After performing authentication, users can generate tickets in the current session by using the SessionFactory.

factory.makeTicket("username", "password", "http://streamfinder", "clientId");

makeTicket will retrieve the session and create a new ticket in it.

On network errors, the future completes exceptionally with UnknownHostException or ConnectionException. If authentication fails or the session has expired, the future completes exceptionally with AuthenticationException.

Discovering Streams

To discover a list of available streams, users first need to create a Discoverer object. This discoverer object can be created by injecting a discoverer factory and calling the create function.

@Inject
public void setDiscovererFactory(DiscovererFactory factory) {
    Discoverer discoverer = factory.create("username", "password", "http://streamfinder");
}

Once we have a discoverer object, we can begin to populate it with the query. In this example, the discoverer search for apple and coco.* streams in the fruits (group id 1) group. We query for tcp streams in this java client.

discoverer.discover((byte) 1, "apple").discover((byte) 1, "coco.*").with("tcp");

Retrieve the discovered list of streams and its sources by doing

List<Source> sources = discoverer.getSources();

The sources structure returned is a full snapshot of all available streams. sources returned from here contain a list of permitted streams and the connection URL for each stream.

Users can also attach listeners to get the latest streams when they are updated

discoverer.onUpdate(sources -> {
    System.out.println(sources);
});

The update event is fired when there is a change in stream sources. The sources structure returned by the listener is a full snapshot of all available streams. This structure is similar to the getter method. Note that the callback is executed on the execution context of the streamfinder module.

Users should also setup a listener for error events.

discoverer.onError(error -> {
    error.printStackTrace();
});

On network errors, an UnknownHostException or ConnectionException event is fired. If authentication fails or the session expires, an AuthenticationException is emitted.

Advertising Streams

First, create an Advertiser using an injected advertiser factory.

@Inject
public void setAdvertiserFactory(AdvertiserFactory factory) {
    Advertiser advertiser = factory.create("username", "password", "http://streamfinder");
}

Do not run multiple advertisers with the same user name. This will corrupt the advertisements and cause flickering on the streamfinder server.

Once we have a advertiser, we can begin to populate it with advertisements. In this example, the advertiser publishes an 'apple' and 'orange' stream in the ‘fruits’ group (group id 1) with a level of 0. Both stream are published from tcp://123.123.123.123:9000.

advertiser.advertise((byte) 1, "apple", 0).advertise((byte) 1, "orange", 0).from("tcp://123.123.123.123:9000");

A single advertiser represents a datafront server. As such, all streams published under a single advertiser will be published as available from all connections registered. We can publish streams coming from different connections by separating them into different advertisers. This example shows how 'apple' and 'orange' streams can be advertised to be coming from 2 separate ports.

advertiser1.advertise((byte) 1, "apple", 0).from("tcp://123.123.123.123:9000");
advertiser2.advertise((byte) 1, "orange", 0).from("http://123.123.123.123:9001");

We can attach listeners to handle update events from the advertiser. These events are fired at regular intervals when the adtvertisement is sent to the server.

discoverer.onUpdate(() -> {
    System.out.println("Advert sent to server");
});

Users should also setup a listener for error events.

discoverer.onError(error -> {
    error.printStackTrace();
});

On network errors, an UnknownHostException or ConnectionException event is fired. If authentication fails or the session expires, an AuthenticationException is emitted.

User Permissions

The java streamfinder includes a module to resolve user access permissions. This module will connect to the database and retrieve users with their permission level. Clients can then supply a given stream and check if the user has permission to access it. The permission module can also resolve other parameters such as best level for a user.

Clients first have to retrieve a User object. Users can be queried from the UserRepository singleton by name.

@Inject
public void setUserRepo(UserRepository repo) {
    User user = repo.findFeedUserByName("username");
}

The User object supports various operations. canAccess verifies if the user can access a particular stream.

boolean isAppleAllowed = user.canAccess((byte) 1, "apple");

levelAccessTo finds the best stream level that a user can connect to.

int bestAppleLevel = user.levelAccessTo((byte) 1, "apple");

getConfigIdFor finds the config id that is used to reference per-user configurations.

long configId = user.getConfigIdFor((byte) 1, "apple");

Javascript Client

The js streamfinder library consists of a Discoverer and a SessionFactory.

User authentication is not provided in js SessionFactory. Unlike its java counterpart, the js SessionFactory performs only ticketing calls. Client will have to perform the necessary authentication calls and retrieve authenticated session cookies before using streamfinder js. Failure to authenticate the session will result in errors emitted from the Discoverer and SessionFactory.

Finally, the UserPermissionModule in the java client is not available in the js library.

Installation

Js clients will have to reference the following files in the script tag:

<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://cloud.github.com/downloads/Olical/EventEmitter/EventEmitter-4.0.3.min.js"></script>
<script src="https://gitlab.jayeson.com.sg/feed/jayeson.lib.streamfinder/raw/master/src/main/js/jayeson/discovery/js/discovery.js"></script>

Retrieving and Updating of Tickets

After performing authentication, users can generate tickets in the current session by using the SessionFactory.

SessionFactory.makeTicket("http://streamfinder", "clientId", function(ticket, error) {
    if (ticket.length !== 0) {
        console.log("Ticket for clientId: " + ticket);
    } else if (error.length !== 0) {
        console.log("Unable to retrieve ticket for clientId: " + error);
    }
});

The result of the ticketing call is deposited in the callback function once the operation completes. A successful ticketing call will return a non-empty ticket string. However, if there were errors, the ticket string will be empty and the error param will contain the reason why ticketing has failed.

Discovering Streams

To discover a list of available streams, users first need to create a Discoverer object by supplying the URL of the streamfinder server.

discoverer = new Discoverer("http://streamfinder");

Once we have a discoverer object, we can begin to populate it with the query. In this example, the discoverer search for apple and coco.* streams in the 'fruits' group (group id 1). Since this is a js app running on the browser, we only query for streams served through ws and wss.

discoverer.discover(1, "apple").discover(1, "coco.*").using("ws").using("wss");

Retrieve the current list of streams and its sources by doing

var sources = discoverer.getSources();

The sources structure returned is a full snapshot of all available streams. sources returned from the update event contain a list of permitted streams and the connection URL for each stream. For more information about the structure of sources, see the streamfinder server API.

Users can also attach listeners to get the latest streams when they are updated

discoverer.on("update", function(sources) {
    console.log(sources);
});

The update event is fired when there is a change in stream sources. The sources structure returned by the listener is a full snapshot of all available streams. This structure is similar to the getter method.

Users should also setup a listener for error events.

discoverer.on("error", function() {
    console.log("Error: See console for details");
});

Common errors include starting the discoverer before a session cookie is available or incorrectly retrieving a cookie. Users should check for cookies sent when discovery requests fail.

After hooking up listeners, start the discoverer to begin receiving stream sources.

discoverer.start();