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

random-access-over-mux

v0.0.1006

Published

random-access over protomux channel

Downloads

28

Readme

random-access-over-mux


Support the cause towards decentralization

bitcoin: bc1q9fpu6muvmg5fj76pyzg3ffjrmksnvfj3c0xva6



!! Alpha Stage !!

Transmit any random-access-storage (ras) derived instance over a stream or protomux connection.

Roadmap and Current state:

  • No reconnect logic yet. Once either the file or rpc is closed, have to recreate both the serve and client side.
  • No firewall or middlewares yet.
  • Be able to set readonly or writeonly or even stat-only
  • Suspend not yet supported
  • The loader is pretty slow right now. I'm trying to nail down why.

Although planned, there is no security protocols currently. Only use this between secure mediums and only over secure transports.

Why not hypercore?

I needed connection between two very trusted endpoints (web workers for example) in a web browser and the underlying secret stream hypercore depends on doesn't work in web browser without relay.

You could still use hypercore with this library on the browser as long as you replicate through a relay.



Installation

npm install random-access-over-mux --save

File API

import {serve, connect} from "random-access-over-mux";

To understand what random-access-over-mux is about, you should read about the random-access api . This library simply wraps the api to be served over any stream.

Both sides have nearly same api

ras = serve(stream, randomAccessFactory, [config])

ras = connect(stream, [config])

stream Can be really any stream, socket, another random-access-over-mux instance or a protomux. Since my use-case this api will encounter unframed streams more than framed, I decided to auto-frame the stream with framed-stream. Set config.noFrame=true if you pass in a framed stream.

randomAccessFactory=(mux, config) => {} A function that returns a random-access instance. Serve side only argument.

config

  • protocol=randomAccessChannel Optional protocol name.
  • id Optional binary ID to identify this file / RPC channel
  • noFrame=false If non-protomux stream is passed, will auto frame the stream unless this is set to true.
  • bits=32 When noFrame=false, this will be the size each frame will be in bits. See framed-stream
  • coming soon: timeout=8000 When the other side doesn't respond, close the connection at this timeout.

await ras.opened

The channel and random-access-storage is opened.

await ras.closed

The channel and random-access-storage is closed.

Currently, you need to recreate the serve/connect pair to reopen. This will probably change.

Methods

  • RandomAccessOverMux = await ras.open() | ras.open((error) => {})
  • data = await ras.read(offset, size) | ras.read(offset, size, (error, data) => {})
  • await ras.write(offset, buff) | ras.write(offset, buff, (error) => {})
  • await ras.del(offset, size) | ras.del(offset, size, (error) => {})
  • await ras.truncate(offset) | ras.truncate(offset, (error) => {})
  • stat = await ras.stat() | ras.stat(offset, (error, stat) => {})
  • close = await ras.close() | ras.close((error) => {})
  • await ras.unlink() | ras.unlink((error) => {})

Properties

protomux = ras.mux

Get the underlying muxor handling the random-access rpc connection where you can pass it to other libraries that use mux.

protomux-rpc = ras.rpc

You may add your own rpc methods and make your own requests as long as they don't conflict with already defined ones (e.g. write, read, stat, truncate, del, close).

{} = ras.capability

Get all the capabilities of the ras, on either side.

{
    readable
    writable
    deletable
    truncatable
    statable
}

bool = ras.isServer

Whether the ras is the server or not.

string=ras.protocol

The protocol that the protomux-rpc is using

buffer=ras.id

The id the protomux-rpc is using. If created by loader, this is also the hash of the file.

Single File Example

import net from "node:net";
import {serve, connect} from "random-access-over-mux";
import RAM from "random-access-memory";
// import RAF from "random-access-file";
// import RAI from "@zacharygriffee/random-access-idb";

const server = net.createServer(async socket => {
    // Serve the file. 
    serve(socket,() => new RAM(), {
        protocol: "rac/bartender/reference",
        id: b4a.from("martiniTips.txt")
    });
    
    // serve another file. You can also access the file from server side too.
    const ras = serve(socket,() => new RAM(), {
        protocol: "rac/bartender/reference",
        id: b4a.from("muddling.txt")
    });

    await ras.write(0, b4a.from("Roll the muddler over the mash with the fat part of your hand, don't just smash like a mad-person"));

    ras.read(0, 4, (error, buffer) => b4a.toString(buffer)); // Roll
}).listen(41111);

const stream = net.connect({port: 41111});
await new Promise(resolve => stream.once("connect", resolve));

// ras Operates just like a random-access-storage instance, but remote.
const ras = connect(stream, {
    protocol: "rac/bartender/reference",
    id: b4a.from("martiniTips.txt")
});

await ras.write(0, b4a.from("stir, don't shake the martini. The gin or vodka can be damaged and shards of ice for most martini drinkers is unpleasant."));
// Notice, random-access-over-mux functions can be invoked by callback or promise.
const result = await ras.read(5, 11); // don't shake

stream.destroySoon();

Loader API

import {serve, connect, load} from "random-access-over-mux/loader";

Both sides have nearly same api

loader = serve(stream, fileFactory, [config])

loader = connect(stream, [config])

In addition to config in the 'file api' section the following configuration is available with some differences.

  • protocol=randomAccessChannelLoader Optional protocol name FOR THE LOADER, not the file.
  • id Optional binary ID to identify this LOADER, not the file.
  • fileFactory=(fileName, mux, config) => {} is different from the randomAccessFactory argument from file api. This will receive a 'fileName' as the first argument for you to create a file from.
  • protocolHandler=(fileName) => 'randomAccessChannel'
  • fileHasher=(fileName) => b4a.from(fileName) When a file is requested, this function will turn the fileName into a hash for the id of the channel. By default, the hasher just converts the fileName into its buffer representation.

(file) => {} = load(stream, [config])

load will return a function where you can connect to files from where the connection logic is deferred to the random-access-storage.open function. Loading a file already loaded will return the already loaded file.

See example below of load usage

Methods

raom = await loader.load(fileName) | loader.load(fileName, (err, raom) => {})

This will load the file on the server side, and will return the random-access-over-mux instance where the file API above takes over.

If the file is already loaded, then it will return the loaded file.

returns a random-access-over-mux instance see file api

await loader.unload([fileName]) | loader.unload([fileName], (err) => {})

If unloading from the server, you can omit the filename and it will unload all files. Working on the 'unload all' for client later. Unload the file for this rpc connection.

Loader Example with 'connect'

import {connect, serve} from "random-access-over-mux/loader";
import RAM from "random-access-memory";
// Create a 'ram folder' that acts like a folder of files.
// You could use random-access-file or @zacharygriffee/random-access-idb
// Or any other random access library you find.
const folder = RAM.reusable();

const serveLoader = serve(serverSocket, (fileName) => folder(fileName));
const clientLoader = connect(clientSocket);

// Load a file on either side
// Returns a random-access-over-mux instance (see single file example above)
const ras = await clientLoader.load("wineTastingTips.txt"); 
await ras.write(0, b4a.from("Don't like wine? You're probably drinking it wrong. Aerate your wine, sip it like a hot coffee, roll it around in the glass to vastly improve your wine drinking experience."));
const serveRas = await serveLoader.load("wineTastingTips.txt");
await serveRas.read(52, 6); // Aerate

await serveLoader.unload("wineTastingTips.txt");

Loader Example with 'load'

const folder = RAM.reusable();

const serveLoader = serve(serverSocket, (fileName) => folder(fileName));
const clientLoader = load(clientSocket);

const bittersFile = clientLoader("bitters.txt");
await bittersFile.write(0, b4a.from("aromatic bitters are good to add to any drink, they add an additional component to the drinking experience. Liqour stores typically carry all different kinds."));
await clientLoader("bitters.txt").read(9, 7); // bitters;

Using this repo to test inversion of control (IoC) techniques.

I am also using this library to test out some inversion of control techniques to reduce duplication of code. Many of my libraries I am using the same libraries over and over again bloating my pages. And bundlers have a problem dealing with this.

I have attached a simple method of IoC for this library for now, but I have plans for a more complex way of handling dependencies. I plan on supporting both the IoC and traditional methods of load on my libraries.

Example IoC

    import inject from "random-access-over-mux/ioc";
//  import inject from "random-access-over-mux/loader/ioc";
    // Lets say you have these libraries already loaded elsewhere
    import b4a from "b4a";
    import cenc from "compact-encoding";
    
    const {serve, connect} = await inject({
        ["compact-encoding"]: cenc,
        b4a: b4a
    });
    
    // then proceed to use serve and connect 
    // just like the exammple at the top of this readme
    serve(mux1, () => new RAM);
    const ras = connect(mux2)
    await ras.write(0, b4a.from("use real cherries not maraschino cherries in your old fashion"));
    ras.close();
    

Test it

npm test

Distributed under the MIT license. See LICENSE for more information.