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

locksmith

v0.2.6

Published

Lockstep deterministic state machine synchronization library

Downloads

8

Readme

locksmith

Lockstep deterministic state machine synchronization library

Locksmith is a simple library to synchronize the state between several devices. It's can be used to sync game state, Redux state, etc. It can be used if the target is fully deterministic - Same input should produce same output.

Usage

Connector

First, you need to create a connector to connect between the protocol (Which can be anything) and the synchronizer.

Note that the connector is used to communicate between server and client, synchronizer doesn't support peer to peer protocol yet!

The connector should implement following functions:

  • getHostId() - Returns the host's client ID.
  • getClientId() - Returns the client's own client ID (which is given by the connector)
  • push(data, targetId) - Executes synchronizer.handlePush(data, senderId) on target.
  • ack(data, targetId) - Executes synchronizer.handleAck(data, senderId) on target.
  • connect(data, targetId) - Executes synchronizer.handleConnect(data, senderId) on target. If the connection hasn't made, it should connect to the target.
  • disconnect(targetId) - Executes synchronizer.handleDisconnect(senderId) on target. The connection should be closed, of course.
  • error(data, targetId) - Handles the error. It may send the error to target (Execute synchronizer.handleError(error)), or just print it on the console. Error is a plain string object.

Machine

Then, you need to create a machine object to process the action and the state.

The machine should implement following functions:

  • getState() - Returns serialized machine state.
  • loadState(state) - Loads the serialized state into the machine.
  • run(action) - Runs the action, and mutates the state information.

The state and action should be serializable objects - JSON is preferred, however, anything can be used as long as the connector can process it.

Action

Actions are processed with FIFO order (First-come-first-served), however, still action order conflicts can occur. Machine should be able to process the action normally even if action conflict occurs. Synchronizer should provide a way to sort the actions, but it's work in progress.

Action validation / transformation

Host synchronizer can opt to validate / transform actions by setting actionHandler(action, client): Object property. If it returns undefined (not null), the action will be ignored. Returned object from the function will be used as action instead.

In order to make push function Promise, clientId value must be present. Also, since it must store Promise ID, promiseId value must be not occupied.

Connection validation

Host synchronizer can also opt to connection validation by setting connectionHandler(meta, client): Object property. It should return modified (or original) metadata object, or it should throw an error. If an error is thrown, the connection will be rejected. Client metadata is available via client.meta after the validation (which means it's not available in validation)

Combining

Lastly, combine everything together to create a synchronizer.

You don't need to specify the options in the client, as server sends the options on connection.

Server

import { HostSynchronizer } from 'locksmith';

let machine = new Machine();
let connector = new Connector();

let synchronizer = new HostSynchronizer(machine, connector, {
  dynamic: false,
  dynamicPushWait: 10,
  dynamicTickWait: 10,
  fixedTick: 50,
  fixedBuffer: 1,
  disconnectWait: 10000,
  freezeWait: 1000
});
connector.synchronizer = synchronizer;

synchronizer.start();

Client

import { Synchronizer } from 'locksmith';

let machine = new Machine();
let connector = new Connector();

let synchronizer = new Synchronizer(machine, connector);
connector.synchronizer = synchronizer;

connector.connect();

Pushing actions

let action = {}; // It can be anything
synchronizer.push(action);

Sending connect action

Host (Server) can register a event listener to spawn a connect event.

synchronizer.on('connect', clientId => {
  synchronizer.push({
    type: 'connect',
    id: clientId
    // etc...
  });
});

Same for disconnect, etc.

Events

  • start() - Synchronizer has started.
  • stop() - Synchronizer has stopped.
  • tick(tickId) - Tick has occurred.
  • freeze(clientId) - Synchronizer freezed. clientId is only available on host.
  • unfreeze(clientId) - Synchronizer unfreezed. clientId is only available on host.
  • connect(clientId) - A client has connected. clientId is only available on host.
  • disconnect(clientId) - A client has disconnected. clientId is only available on host.
  • error(error, clientId) - An error has occurred. clientId is only available on host. You must listen to this event to prevent terminating node process!

Configuration

Synchronizer has number of options that changes the behavior of synchronization.

  • dynamic: Boolean - If true, use dynamic mode instead of fixed mode. Dynamic mode trigger the tick only when a client sends actions, thus saving unnecessary data transfer if actions doesn't occur a lot.
  • dynamicPushWait: Number - How much should the client wait to push actions to server?
  • dynamicTickWait: Number - When a push was received, how much should the host wait to trigger a tick?
  • fixedTick: Number - How often does the tick happen in fixed mode?
  • fixedBuffer: Number - How many ticks should the client buffer?
  • disconnectWait: Number - How long should the host wait to disconnect not responding client?
  • freezeWait: Number - How long should the host wait for acknowledge without freezing?