{"id":13482600,"url":"https://github.com/ssbc/muxrpc","last_synced_at":"2025-03-27T13:32:15.385Z","repository":{"id":21994573,"uuid":"25319601","full_name":"ssbc/muxrpc","owner":"ssbc","description":"lightweight multiplexed rpc","archived":false,"fork":false,"pushed_at":"2023-11-21T10:17:03.000Z","size":231,"stargazers_count":99,"open_issues_count":5,"forks_count":13,"subscribers_count":20,"default_branch":"main","last_synced_at":"2024-04-14T08:50:04.212Z","etag":null,"topics":["codec","javascript","manifest","protocol","rpc","streams"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-10-16T20:09:08.000Z","updated_at":"2023-10-13T09:57:33.000Z","dependencies_parsed_at":"2024-01-06T23:56:57.759Z","dependency_job_id":"d18d6c8f-fdfe-4263-a4e9-13bbffd2630e","html_url":"https://github.com/ssbc/muxrpc","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fmuxrpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fmuxrpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fmuxrpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fmuxrpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssbc","download_url":"https://codeload.github.com/ssbc/muxrpc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221839990,"owners_count":16889705,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codec","javascript","manifest","protocol","rpc","streams"],"created_at":"2024-07-31T17:01:03.641Z","updated_at":"2024-10-30T16:31:26.080Z","avatar_url":"https://github.com/ssbc.png","language":"JavaScript","readme":"# muxrpc\n\ncombined rpc and multiplexing, with pull-streams.\n\n[![build status](https://secure.travis-ci.org/ssbc/muxrpc.png)](http://travis-ci.org/ssbc/muxrpc)\n\n\n## motivation\n\n`muxrpc` aims to provide remote access to any reasonable node.js api remotely.\nthis means it supports both streaming and async operations.\n[pull-streams](https://github.com/pull-stream/pull-stream) are used.\n\nIt may seem at first that it would be logically cleaner to separate this into two concerns,\nmultiplexing and request-response. Indeed, we did just that in [multilevel](https://github.com/juliangruber/multilevel)\ncombining [mux-demux](http://github.com/dominictarr/mux-demux) and [rpc-stream](http://github.com/dominictarr/rpc-stream)\nhowever, I realized that multiplexing depends on adding framing to incoming messages,\nand so does rpc. If rpc is implemented as another layer on top of multiplexing, then the rpc messages\nend up with a second layer of framing too. By implementing one protocol that supports both streams\nand rpc, we were able to have both features with only a single layer of framing.\n\n## example\n\n```js\nconst Muxrpc = require('muxrpc')\nconst pull = require('pull-stream')\nconst toPull = require('stream-to-pull-stream')\n\n//we need a manifest of methods we wish to expose.\nconst manifest = {\n  //async is a normal async function\n  hello: 'async',\n\n  //source is a pull-stream (readable)\n  stuff: 'source'\n\n  //TODO: sink and duplex pull-streams\n}\n\n//the actual methods which the server exposes\nconst api = {\n  hello(name, cb) {\n    cb(null, 'hello, ' + name + '!')\n  },\n  stuff() {\n    return pull.values([1, 2, 3, 4, 5])\n  }\n}\n\n//pass the manifests into the constructor, and then pass the local api object you are wrapping\n//(if there is a local api)\nconst client = Muxrpc(manifest, null)\nconst server = Muxrpc(null, manifest, api)\n```\n\nnow set up a server, and connect to it...\n\n```js\nconst net = require('net')\n\nnet.createServer(stream =\u003e {\n  stream = toPull.duplex(stream) //turn into a pull-stream\n  //connect the output of the net stream to the muxrpc stream\n  //and then output of the muxrpc stream to the net stream\n  pull(stream, server.stream, stream)\n}).listen(8080)\n//connect a pair of duplex streams together.\n\nconst stream = toPull.duplex(net.connect(8080))\n\npull(stream, client.stream, stream)\n\n// Now you can call methods like this.\nclient.hello('world', function (err, value) {\n  if (err) throw err\n  console.log(value)\n  // hello, world!\n})\n\n// Alternatively, you can use the promise syntax.\nclient.hello('world').then((value) =\u003e {\n  console.log(value)\n})\n\npull(client.stuff(), pull.drain(console.log))\n// 1\n// 2\n// 3\n// 4\n// 5\n```\n\n## protocol\n\nAs indicated by the name, `muxrpc` combines both multiplexing and rpc (remote procedure call,\ni.e. request-response). The protocol is described in details in [rpc protocol section of the protocol guide](https://ssbc.github.io/scuttlebutt-protocol-guide/#rpc-protocol)\n\n## Api: createMuxrpc (remoteManifest, localManifest, localApi, perms, codec) =\u003e rpc\n\n- `remoteManifest` the manifest expected on the remote end of this connection.\n- `localManifest` the manifest of the methods we are exposing locally.\n- `localApi` the actual methods we are exposing - this is on object with function with call types\nthat match the manifest.\n- `perms` a permissions object with `{test: function (path, type, args) {} }` function.\n- `codec` stream encoding. defaults to [packet-stream-codec](https://github.com/ssbc/packet-stream-codec)\n\n### rpc\n\nan [EventEmitter](https://devdocs.io/node/events#events_class_eventemitter)\ncontaining proxies for all the methods defined in your manifest, as well as the following:\n\n* `stream`\n* `closed` a boolean, wether the instance is closed.\n* `close` an async method to close this connection, will end the `rpc.stream`\n\nAnd every method provided in the manifest. If a method in the manifest has the same\nname as a built in, the built in will override the manifest, and you will not be able\nto call that remove method.\n\n## Manifest\n\n`muxrpc` works with async functions, sync functions, and pull-streams.\nBut that javascript is dynamic, we need to tell muxrpc what sort of method\nshould be at what api, that is what the \"mainfest\" is for.\nThe manifest is simply an object mapping a key to one of the strings \"sync\" \"async\" \"source\" \"sink\" or \"duplex\",\nor a nested manifest.\n\n``` js\n{\n  foo: 'async',        //a function with a callback.\n  bar: 'sync',         //a function that returns a value\n                       //(note this is converted to an async function for the client)\n  allTheFoos: 'source' //a source pull-stream (aka, readable)\n  writeFoos: 'sink',   //a sink pull-stream (aka, writable)\n  fooPhone: 'duplex',  //a duplex pull-stream\n\n  //create nested objects like this:\n  bar: {\n    ...\n  }\n}\n\n```\n\n## Permissions\n\nmuxrpc includes a helper module for defining permissions.\nit implements a simple allow/deny list to define permissions for a given connection.\n\n```js\nconst Permissions = require('muxrpc/permissions')\n\nconst manifest = {\n  foo: 'async',\n  bar: 'async',\n  auth: 'async'\n}\n\n//set initial settings\nconst perms = Perms({allow: ['auth']})\n\nconst rpc = muxrpc(null /* no remote manifest */, manifest, {\n  foo: function (val, cb) {\n    cb(null, {okay: 'foo'})\n  },\n  bar: function (val, cb) {\n    cb(null, {okay: 'bar'})\n  },\n  auth: function (pass) {\n    // implement an auth function that sets the permissions,\n    // using allow or deny lists.\n\n    if(pass === 'whatever')\n      perms({deny: ['bar']}) // allow everything except \"bar\"\n    else if(pass === 's3cr3tz')\n      perms({}) // allow everything!!!\n    else return cb(new Error('ACCESS DENIED'))\n\n    //else we ARE authorized.\n    cb(null, 'ACCESS GRANTED')\n  }\n}, perms, serializer) // pass the perms object to the second argument of the constructor.\n\n// Get a stream to connect to the remote. As in the above example!\nvar ss = rpc.stream\n```\n\n## bootstrapping - automatically loading the remote manifest.\n\nSometimes you don't know the remote manifest yet. If you pass a callback\ninstead of `remoteManifest`, then an async method `manifest` is called on the\nremote, which should return a manifest. This then used as the remote manifest\nand the callback is called.\n\n```js\nconst manifest = { hello: 'sync', manifest: 'sync' }\n\nconst alice = Muxrpc(null, manifest, {\n  hello: function (message) {\n    if(this._emit) this._emit('hello', message)\n    console.log(`${this.id} received ${message}`)\n    return `${message} to you too`\n  },\n  manifest: function () {\n    return manifest\n  }\n})\n\nconst bob = Muxrpc(function (err, manifest) {\n  if (err) throw err\n\n  // Bob now knows Alice's API\n  console.log(manifest) // =\u003e { hello: 'sync', manifest: 'sync' }\n\n  bob.hello('aloha', (err, val) =\u003e {\n    if (err) throw err\n    console.log(val) // =\u003e \"aloha to you too\"\n  })\n})\n\npull(bob.stream, alice.stream, bob.stream)\n```\n\n## License\n\nMIT\n","funding_links":[],"categories":["Modules","JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fmuxrpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssbc%2Fmuxrpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fmuxrpc/lists"}