ssbc / ssb-conn

SSB plugin for establishing and managing peer connections
MIT License
16 stars 5 forks source link

How should I get a [non-stream] list of connected peers? #9

Closed christianbundy closed 4 years ago

christianbundy commented 4 years ago

Previously ssb-server status had a gossip section that listed the connected peers, which was useful for debugging. I'd like to do something similar, but all I'm seeing in the API is a stream interface. I'm sure I could build an interface that converted the stream to an async/sync call, but I'm sure this is a solved problem.

staltz commented 4 years ago

I think you'll find the answer quickly in ssb-conn-query docs and you have access to that via ssb.conn.query().____

christianbundy commented 4 years ago

Thanks! Is that also available via the CLI? I've tried ssb-server conn.peers but it doesn't seem to exit (because it's a stream). I read through the docs and found conn-query, but couldn't figure out how to call it from the CLI.

staltz commented 4 years ago

Hmm, interesting, I haven't tested it at all from the CLI. I wonder how do these APIs even work from the CLI?

christianbundy commented 4 years ago

My understanding is that muxrpcli takes a command like widget.get --foo bar and calls conn.get({ foo: 'bar' }) over muxrpc.

I think the trouble is that we're instead doing conn.connQuery().peersAll(), and muxrpcli doesn't have the ability to chain methods.

staltz commented 4 years ago

Hmm, that's unfortunate. Gladly this whole SSB CONN is still pre-v1.0 precisely because I wanted to see how people use it in different ways and contexts and readapt the API to allow for those use cases. I'll think about this one for a bit. Any suggestions?

christianbundy commented 4 years ago

I haven't spent much time looking at the code, but this seems contradictory:

https://github.com/staltz/ssb-conn/blob/fb1711adaf5124aa37128614e7c6caf47756fd97/src/conn.ts#L19

https://github.com/staltz/ssb-conn/blob/fb1711adaf5124aa37128614e7c6caf47756fd97/src/conn.ts#L186

My first stab at this would probably look like:

export class CONN {
  public readonly query: ConnQuery;

  constructor() {
    this.query = new ConnQuery(this._db, this._hub, this._staging);
  }
}

Thinking about this more though, I'm sure that would require adding @muxrpc decorators throughout ConnQuery and then exporting all of those in ssb-conn's manifest file. It seems like conn.query() works great when you're calling it from the same Node process, but when you call it from another process (or another computer) via muxrpc then you only receive the data that can be serialized as JSON (i.e. not functions).

Happy to have a chat or call about this if you'd like, seems like kind of a hairy problem.

staltz commented 4 years ago

The public property query would not be available via muxrpc because muxrpc only supports sync method (which query() is), async function, and then pull streams like source, duplex, etc.

But it's possible that query() via muxrpc is useless over other processes, I haven't tested that use case.

One design goal I had with this is to not expose all of ConnDB, ConnHub, ConnStaging, ConnQuery APIs over muxrpc, but instead the goal was to make those be just tools that we use inside CONN, which in turn provides a very simple and limited API to the UI. Finding the right APIs for the UI is a bit challenging.

If the goal of this issue is to only cover the CLI use case of ssb-server status or something like that, then I think that is a decent thing to pursue. Is this issue specifically about CLI or is it about how to get the list of peers? If it's about CLI we could reopen. In general I'm curious what are all the use cases we need to cover for CLI.

christianbundy commented 4 years ago

The public property query would not be available via muxrpc

I think you'd just need to add it as a nested property in the manifest file, maybe?

{
  "conn": {
    "query": {
      "peersAll": "sync"
    }
  }
}

But it's possible that query() via muxrpc is useless over other processes, I haven't tested that use case.

Right, I think this is the problem I'm having because I'm using muxrpc to connect to the server. When you call conn.query() over muxrpc you get:

{
  db: {
    _map: {},
    _stateFile: {},
    _writeTimeout: 1000,
    _scheduledWriteTask: null,
    _closed: false,
    _loadedPromise: {}
  },
  hub: {
    _server: {
      _events: [Object],
      _eventsCount: 4,
      peers: [Object],
      config: [Object],
      multiserver: {},
      id: '@+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=.ed25519',
      publicKey: '@+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=.ed25519',
      keys: [Object],
      replicate: {},
      about: {},
      backlinks: {},
      blobs: {},
      conn: {},
      gossip: {},
      connScheduler: {},
      ebt: {},
      friends: {},
      invite: {},
      lan: {},
      links2: [Object],
      plugins: {},
      query: [Object],
      tangle: {},
      ws: {}
    },
    _closed: false,
    _connectRetries: {},
    _peers: {}
  },
  staging: { _peers: {}, _closed: false }
}

Is this issue specifically about CLI or is it about how to get the list of peers?

It's about how to get a list of peers over muxrpc, which would make it possible in the CLI and every other app that connects to the server over muxrpc.

Since conn.peers() emits an entire array, maybe I could hack together a workaround with pull.take(1), but it would be great to have an async or sync method instead of hacking a stream.

staltz commented 4 years ago

@christianbundy I've been thinking about this issue sometimes, and I think as a principle I prefer to go with A few primitives which you can use to compose with other primitives to achieve what you want, instead of All the possible outcomes you may want, each one as an API.

So this means that programmatically you could use pull(ssb.conn.peers(), pull.take(1), pull.drain(cb)) to get just the current list of connected peers. And for CLI support, I believe CLI commands should be built centralized in one place (e.g. perhaps some package ssb-cli or perhaps this is ssb-server's concern) than decentralized (meaning that every other ssb-* package has to expose itself for CLI usage covering all the possible CLI use cases). In that case, if some other package takes ownership over the CLI problem, then it can programmatically utilize ssb-conn to provide the commands, and thus it would have full access to all ssb-conn APIs.