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

sock-daemon

v1.4.2

Published

A utility for creating a daemon process that listens on a socket, and a client that talks to it.

Downloads

60,657

Readme

sock-daemon

A utility for creating a daemon process that listens on a socket, and a client that talks to it.

Handles automatically starting the daemon service (but only one of them), logging to a file, and serializing messages over a domain socket on unix systems or named pipe on Windows.

USAGE

Install with npm

npm install sock-daemon

There are two parts of this, the daemon script that listens on a socket, and the client that connects to it.

The daemon is smart enough to only instantiate a single copy of itself. The client knows how to connect to it, and knows how to spin up an instance of the daemon if it's not already running.

To do this, the server daemon and the client need to both know the name that they'll use for the socket, and the client needs to know the location of the daemon script.

The type stuff is clearly only required when you are using TypeScript, but it is a nice check to ensure that the server and client are speaking the same language.

For example, you can create a service like this, defining a client and server implementation:

// index.mjs
import {
  SockDaemonServer as Server,
  SockDaemonClient as Client,
} from 'sock-daemon'
import type { MessageBase } from 'sock-daemon'

export const serviceName = 'my-service'

// This must be an object that extends MessageBase
export interface Request extends MessageBase {
  // put your application specific types here for requests
  foo: string
}

export interface Response extends MessageBase {
  // put your application specific types here for responses
  bar: string
}

// create my application specific server to handle requests
export class MyServiceServer extends Server<Request, Response> {
  // check here to ensure that the request is valid
  // anything that fails this will be logged and
  isRequest(msg: any): msg is Request {
    return super.isMessage(msg) && typeof msg.foo === 'string'
  }

  // must override this static property to set the service name
  // the socket, pidFile, and log will be found in
  // .{service-name}/daemon/... in the current working dir
  static get serviceName() {
    return serviceName
  }

  // get a request, return a response.
  // must return either Response or Promise<Response>
  async handle(msg: Request) {
    // stderr will be written to ./.my-service/daemon/log when
    // spawned automatically by the client.
    console.error('got request', msg)
    // must return a response with the same ID we got in the
    // request, to handle replayed or out of order messages
    return {
      id: msg.id,
      bar: 'bar: ' + msg.foo,
    }
  }
}

export class MyServiceClient extends Client<Request, Response> {
  // this must match what's defined in the daemon server
  static get serviceName() {
    return serviceName
  }

  // the path to the node script that starts the daemon
  // either a URL or a file path.
  static get daemonScript() {
    return new URL('./daemon.mjs', import.meta.url)
  }

  // optional, validate that a response is valid
  // if this returns false, the request promise will reject
  isResponse(msg: any): msg is Response {
    return super.isMessage(msg) && typeof msg.bar === 'string'
  }

  // define whatever methods you like here, but they all need to
  // eventually call super.request() to send the actual request.
  // the argument to super.request() MUST NOT include an id, that
  // is managed by the SockDaemonClient base class.
  async fooIntoBar(foo: string) {
    const { bar } = await super.request({ foo })
    return bar
  }
}

Create the daemon.mjs script like this:

import { MyServiceServer } from './index.mjs'

// instantiate the server daemon. Options are optional,
// shown here with their default values.
const server = new MyServiceServer({
  // how long in ms should the daemon stick around if it hasn't
  // seen any requests? Defaults to 1 hour
  idleTimeout: 1000 * 60 * 60,

  // how long should a connection be allowed to persist, if it
  // has not made any requests? Defaults to 1 second
  connectionTimeout: 1000,
})

server.listen()

And then using the client in a program somewhere:

import { MyServiceClient as Client } from 'my-service'

const client = new Client()
// starts the daemon, if it's not already running
const result = await client.fooIntoBar('input string')
// returns: "bar: input string"

API

See the above example for most of it, or look at the typedocs

Caveats

  • Note that your Daemon and Client classes need to override the static serviceName getter to a matching value, and the Client needs to override the static daemonScript to a reference to the node program that will run the service.
  • The daemonScript will be passed to node with the process.execArgv provided to the main client program, but no other arguments.
  • This will work best if your messages can be as small as possible, to save on serialization costs. If you have to do some large amount of work, it's often faster to write the result to a file, and have the Response report the filename.
  • To my knowledge, this module is not responsible for anyone's missing socks, but please post an issue if you find this is not the case.