Options
All
  • Public
  • Public/Protected
  • All
Menu

Package enchannel-zmq-backend

enchannel-zmq-backend

Installation | Usage | Contributors and developers | Learn more about nteract

enchannel-zmq-backend offers the ZeroMQ backend implementation for enchannel.

Technical overview

As a refresher for the reader, enchannel details nteract's lightweight, implementation-flexible specification for communication between a user frontend and a backend, such as a language kernel. The enchannel specification offers a simple description of "what" messages may be passed between frontends and backends, while leaving a developer freedom in "how" to achieve message communication.

enchannel-zmq-backend takes a classic design approach using ZeroMQ, the foundation messaging protocol for the Jupyter project. enchannel-zmq-backend implements backend support for the messaging channels described in the Jupyter messaging specification. This spec explains how front end clients should communicate with backend language kernels which implement the Jupyter messaging specification.

Our backend

enchannel-zmq-backend implements the "how" to communicate messages to and from a backend.

We provide functions to create RxJS Subjects (two way Observables for four of the channels described in the Jupyter messaging specification):

  • shell
  • control
  • iopub
  • stdin

That's it. Functions for four channels; simplicity in action.

Installation

Prerequisite: Node.js and npm

You may use whichever package manager (npm or yarn) best suits your workflow. The nteract team internally uses yarn.

npm install enchannel-zmq-backend
# OR
yarn add enchannel-zmq-backend

Usage

Creating messaging channels

To get access to all of the channels for messaging (shell, control, iopub, and stdin), import and use the createChannels function:

import { createChannels } from 'enchannel-zmq-backend'

The createChannels function accepts two things:

  • an identity

    You'll want to set up your identity, relying on the node uuid package:

      const uuidv4 = require('uuid/v4');
      const identity = uuidv4();
  • a runtime object, such as a kernel (which matches the on-disk JSON). Using spawnteract with this project helps streamline spawning a kernel.

      const runtimeConfig = {
        stdin_port: 58786,
        ip: '127.0.0.1',
        control_port: 58787,
        hb_port: 58788,
        signature_scheme: 'hmac-sha256',
        key: 'dddddddd-eeee-aaaa-dddd-dddddddddddd',
        shell_port: 58784,
        transport: 'tcp',
        iopub_port: 58785
      }

To create the channels object:

const channels = createChannels(identity, runtimeConfig)
const { shell, iopub, stdin, control } = channels;

enchannel-zmq-backend also gives access to all of the channels via a single multipled channel exposed via createMainChannel.

import { createMainChannel } from 'enchannel-zmq-backend';

Similar to the createChannels function, the createMainChannel function accepts both an identity and a runtime object.

const channel = createMainChannel(identity, runtimeConfig);

Messages that are sent via the mutliplexed channel need to define a type property that outlines which channel they should be sent under.

const body = {
    header: {
        msg_id: `execute_9ed11a0f-707e-4f71-829c-a19b8ff8eed8`,
        username: "rgbkrk",
        session: "00000000-0000-0000-0000-000000000000",
        msg_type: "execute_request",
        version: "5.0"
    },
    content: {
        code: 'print("woo")',
        silent: false,
        store_history: true,
        user_expressions: {},
        allow_stdin: false
    }
};
const message = { type: "shell", body };

enchannel-zmq-backend also offers four convenience functions to easily create the messaging channels for control, stdin, iopub, and shell :

import {
  createControlSubject,
  createStdinSubject,
  createIOPubSubject,
  createShellSubject,
} from 'enchannel-zmq-backend';

Creating a subject for the shell channel:

const shell = createShellSubject(identity, runtimeConfig)

Subscribing to messages

Here's an example about how to subscribe to iopub messages:

const iopub = createIOPubSubject(identity, runtimeConfig);
var subscription = iopub.subscribe(msg => {
  console.log(msg);
}

// later, run subscription.unsubscribe()

Since these channels are RxJS Observables, you can use filter, map, scan and many other RxJS operators:

iopub.filter(msg => msg.header.msg_type === 'execute_result')
     .map(msg => msg.content.data)
     .subscribe(x => { console.log(`DATA! ${util.inspect(x)}`)})

Sending messages to the kernel

Executing code will rely on sending an execute_request to the shell channel.

var message = {
  header: {
    msg_id: `execute_9ed11a0f-707e-4f71-829c-a19b8ff8eed8`,
    username: 'rgbkrk',
    session: '00000000-0000-0000-0000-000000000000',
    msg_type: 'execute_request',
    version: '5.0',
  },
  content: {
    code: 'print("woo")',
    silent: false,
    store_history: true,
    user_expressions: {},
    allow_stdin: false,
  },
};

Currently, you'll need to have at least one subscription activated before you can send on a channel.

> shell.subscribe(console.log)
> shell.next(message)
> Message {
  header:
   { username: 'rgbkrk',
     msg_type: 'execute_reply',
     msg_id: '0f6d37f3-56a2-41fd-b3ed-90cc189ac423',
     version: '5.1',
     session: '40472e70-e008-48d1-9537-55837a905c05',
     date: '2016-01-12T00:39:44.686986' },
  parent_header:
   { username: 'rgbkrk',
     session: '00000000-0000-0000-0000-000000000000',
     version: '5.0',
     msg_id: 'execute_9ed11a0f-707e-4f71-829c-a19b8ff8eed8',
     msg_type: 'execute_request' },
  metadata:
   { dependencies_met: true,
     engine: '34d73425-4f04-4b57-9bc7-b46e3100e1fd',
     status: 'ok',
     started: '2016-01-12T00:39:44.684534' },
  content:
   { status: 'ok',
     execution_count: 60,
     user_expressions: {},
     payload: [] } }

Contributors and developers

ZeroMQ Dependency

If you plan to contribute to this project or extend it, you will need to have ZeroMQ installed on your system. The easiest way to do this is to install nteract's zmq-prebuilt[] binary for your operating system.

Install a local development environment

To set up a development environment, you'll need to install:

Then, fork and clone this repo:

git clone https://github.com/nteract/enchannel-zmq-backend.git
cd enchannel-zmq-backend
yarn

Develop! We welcome new and first time contributors.

Learn more about nteract

nteract animated logo

Index

Type aliases

ChannelName

ChannelName: "iopub" | "stdin" | "shell" | "control"

Functions

Message

  • Message(properties: object): void

Const createMainChannel

  • Creates a multiplexed set of channels.

    Parameters

    • config: JupyterConnectionInfo

      Jupyter connection information

    • Default value subscription: string = ""

      subscribed topic; defaults to all

    • Default value identity: string = uuid()

      UUID

    • Default value header: HeaderFiller = {session: uuid(),username: getUsername()}
    • Default value jmp: any = moduleJMP

    Returns Promise<Channels>

    Subject containing multiplexed channels

Const createMainChannelFromSockets

  • Creates a multiplexed set of channels.

    Parameters

    • sockets: object

      An object containing associations between channel types and 0MQ sockets

      • [name: string]: moduleJMP.Socket
    • Default value header: HeaderFiller = {session: uuid(),username: getUsername()}

      The session and username to place in kernel message headers

    • Default value jmp: any = moduleJMP

      A reference to the JMP Node module

    Returns Channels

    Creates an Observable for each channel connection that allows us to send and receive messages through the Jupyter protocol.

Const createSocket

  • Creates a socket for the given channel with ZMQ channel type given a config

    Parameters

    • channel: ChannelName

      Jupyter channel ("iopub", "shell", "control", "stdin")

    • identity: string

      UUID

    • config: JupyterConnectionInfo

      Jupyter connection information

    • Default value jmp: any = moduleJMP

    Returns Promise<moduleJMP.Socket>

    The new Jupyter ZMQ socket

Const createSockets

  • createSockets(config: JupyterConnectionInfo, subscription?: string, identity?: any, jmp?: any): Promise<object>
  • Sets up the sockets for each of the jupyter channels.

    Parameters

    • config: JupyterConnectionInfo

      Jupyter connection information

    • Default value subscription: string = ""

      The topic to filter the subscription to the iopub channel on

    • Default value identity: any = uuid()

      UUID

    • Default value jmp: any = moduleJMP

      A reference to the JMP Node module

    Returns Promise<object>

    Sockets for each Jupyter channel

Const formConnectionString

  • Takes a Jupyter spec connection info object and channel and returns the string for a channel. Abstracts away tcp and ipc connection string formatting

    Parameters

    Returns string

    The connection string

Const getUsername

  • getUsername(): string

Const verifiedConnect

  • verifiedConnect(socket: moduleJMP.Socket, url: string): Promise<moduleJMP.Socket>
  • Ensures the socket is ready after connecting.

    Parameters

    • socket: moduleJMP.Socket

      A 0MQ socket

    • url: string

      Creates a connection string to connect the socket to

    Returns Promise<moduleJMP.Socket>

    A Promise resolving to the same socket.

Object literals

Const ZMQType

ZMQType: object

frontend

frontend: object

control

control: string = "dealer"

iopub

iopub: string = "sub"

shell

shell: string = "dealer"

stdin

stdin: string = "dealer"

Generated using TypeDoc