Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 4dde0f8

Browse files
committed
chore: add docs and fix typos
1 parent a7483bf commit 4dde0f8

File tree

6 files changed

+222
-4
lines changed

6 files changed

+222
-4
lines changed

Diff for: .travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ jobs:
177177
- stage: test
178178
name: js-ipfs interface tests - ipfs-client - chrome webworker
179179
script:
180-
- npm run test:interface:coclientre -- $RUN_SINCE -- -- --bail -t webworker --timeout 60000
180+
- npm run test:interface:client -- $RUN_SINCE -- -- --bail -t webworker --timeout 60000
181181

182182
- stage: test
183183
name: js-ipfs interface tests - ipfs-client - firefox

Diff for: packages/interface-ipfs-core/src/add-all.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const { isNode } = require('ipfs-utils/src/env')
1515
const { getDescribe, getIt, expect } = require('./utils/mocha')
1616
const testTimeout = require('./utils/test-timeout')
1717
const uint8ArrayFromString = require('uint8arrays/from-string')
18-
const delay = require('delay')
1918

2019
/** @typedef { import("ipfsd-ctl/src/factory") } Factory */
2120
/**
@@ -437,6 +436,9 @@ module.exports = (common, options) => {
437436

438437
await new Promise((resolve) => {
439438
const interval = setInterval(() => {
439+
// we've received a progress result, that means we've received some
440+
// data from the server before we're done sending data to the server
441+
// so the streaming is bidirectional and we can finish up
440442
if (progressInvoked) {
441443
clearInterval(interval)
442444
resolve()
@@ -468,7 +470,7 @@ module.exports = (common, options) => {
468470

469471
await expect(drain(ipfs.addAll(source(), {
470472
fileImportConcurrency: 1,
471-
chunker: 'rabin-2048--50' // invalid chunker parameters
473+
chunker: 'rabin-2048--50' // invalid chunker parameters, validated after the stream starts moving
472474
}))).to.eventually.be.rejectedWith(/Chunker parameter avg must be an integer/)
473475
})
474476
})

Diff for: packages/ipfs-client/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# ipfs-client
2+
3+
> A client for [ipfs][] daemons
4+
5+
This module combines the [ipfs-grpc-client][] and [ipfs-http-client][] modules to give you a client that is capable of bidirectional streaming in the browser as well as node.
6+
7+
## Install
8+
9+
```console
10+
$ npm install ipfs-client
11+
```
12+
13+
## API
14+
15+
The client object created by the `createClient` function supports the [IPFS Core API](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api), see the docs for more.
16+
17+
### `createClient([options])`
18+
19+
### Parameters
20+
21+
None
22+
23+
### Options
24+
25+
An optional object which may have the following keys:
26+
27+
| Name | Type | Default | Description |
28+
| ---- | ---- | ------- | ----------- |
29+
| grpc | `Multiaddr` or `string` or `URL` | `undefined` | The address of a [ipfs-grpc-server][] to connect to |
30+
| http | `Multiaddr` or `string` or `URL` | `undefined` | The address of a [ipfs-http-server][] to connect to |
31+
32+
### Returns
33+
34+
| Type | Description |
35+
| -------- | -------- |
36+
| `object` | An instance of the client |
37+
38+
### Example
39+
40+
```js
41+
const createClient = require('ipfs-client')
42+
43+
const client = createClient({
44+
grpc: '/ipv4/127.0.0.1/tcp/5003/ws',
45+
http: '/ipv4/127.0.0.1/tcp/5002/http'
46+
})
47+
48+
const id = await client.id()
49+
```
50+
51+
[ipfs]: https://www.npmjs.com/package/ipfs
52+
[ipfs-grpc-client]: https://www.npmjs.com/package/ipfs-grpc-client
53+
[ipfs-http-client]: https://www.npmjs.com/package/ipfs-http-client
54+
[ipfs-grpc-server]: https://www.npmjs.com/package/ipfs-grpc-server
55+
[ipfs-http-server]: https://www.npmjs.com/package/ipfs-http-server

Diff for: packages/ipfs-grpc-client/README.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# ipfs-grpc-client
2+
3+
> A client for the [ipfs-grpc-server][] module
4+
5+
This module implements part of the [IPFS Core API](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api) using gRPC over websockets to achieve the bidirectional streaming necessary to have full duplex streams running in the browser.
6+
7+
It's not recommended you use this directly, instead use the [ipfs-client](https://www.npmjs.com/package/ipfs-client) to combine this with the [ipfs-http-client](https://www.npmjs.com/package/ipfs-http-client) in order to have HTTP fallback for the missing parts of the API.
8+
9+
## Why?
10+
11+
The [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) APIs do not allow for full-duplex streaming, that is, allowing the client to receive bytes from the response while also adding more bytes to the outgoing request.
12+
13+
This limits what we can do in browsers in terms of the API, for example streaming arbitrarily sized payloads or exposing libp2p duplex streams.
14+
15+
gPRC over websockets has no such limitations so allows us to harness the full power of a remote IPFS node in the browser without the need to work around browser behaviour.
16+
17+
## Install
18+
19+
```console
20+
$ npm install ipfs-grpc-client
21+
```
22+
23+
## API
24+
25+
### `createClient([options])`
26+
27+
### Parameters
28+
29+
None
30+
31+
### Options
32+
33+
An optional object which may have the following keys:
34+
35+
| Name | Type | Default | Description |
36+
| ---- | ---- | ------- | ----------- |
37+
| url | `Multiaddr` or `string` or `URL` | `undefined` | The address of a [ipfs-grpc-server][] to connect to |
38+
39+
### Returns
40+
41+
| Type | Description |
42+
| -------- | -------- |
43+
| `object` | An instance of the client |
44+
45+
### Example
46+
47+
```js
48+
const createClient = require('ipfs-gprc-client')
49+
50+
const client = createClient({
51+
url: '/ipv4/127.0.0.1/tcp/1234/ws'
52+
})
53+
54+
const id = await client.id()
55+
```
56+
57+
[ipfs-grpc-server]: https://www.npmjs.com/package/ipfs-grpc-server

Diff for: packages/ipfs-grpc-client/src/core-api/add-all.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ module.exports = function grpcAddAll (grpc, opts = {}) {
9999

100100
const client = grpc.client(Root.addAll, {
101101
host: opts.url,
102-
debug: true
102+
debug: Boolean(process.env.DEBUG)
103103
})
104104

105105
setTimeout(() => {

Diff for: packages/ipfs-grpc-server/README.md

+104
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
> A gRPC server that runs over a websocket
44
5+
## Why?
6+
7+
[gRPC-web](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md) allows us to form HTTP requests out of gRPC invocations, but the [official implementation](https://github.com/grpc/grpc-web) supports only unary calls and server streaming, which in terms of functionality doesn't give us much over the existing [ipfs-http-client](https://www.npmjs.com/package/ipfs-http-client).
8+
9+
In order to support streaming file uploads with errors, pubsub, etc, bi-directional streaming is required. We can either use Websockets for this, or use two connections, one for upload and one for download though this involves two requests for every operation and some orchestration on the server side to match one up with the other.
10+
11+
Websockets are a cheaper and simpler way of accomplishing the same thing though sadly the official gRPC implementation has [no plans](https://github.com/grpc/grpc-web/blob/master/doc/streaming-roadmap.md#issues-with-websockets) to implement full-duplex streaming in this way.
12+
13+
This module implements a Websocket proxy for a gRPC-web server. It's largely a js port of the [grpcwebproxy](https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy) project from [improbable-eng/grpc-web](https://github.com/improbable-eng/grpc-web).
14+
515
## Protocol
616

717
Every message sent to or received from the server will have the following format:
@@ -43,3 +53,97 @@ A five-byte field that contains one byte signifying if it's a Header or a Traile
4353
|--------------|---|
4454
| 0 | 0: This is a header, 128: This is a footer |
4555
| 1-4 | A big-endian 32-bit integer that specifies the length of the trailer |
56+
57+
## Handlers
58+
59+
Method handlers come in four flavours - unary, server streaming, client streaming, bidirectional streaming and accept metadata as an argument.
60+
61+
### Metadata
62+
63+
All methods accept metadata which are sent as the equivalent of HTTP headers as part of every request. These are accepted by the client as options to a given method.
64+
65+
E.g.:
66+
67+
```js
68+
ipfs.addAll(source, options)
69+
// `source` will be turned into a message stream
70+
// `options` will be sent as metadata
71+
```
72+
73+
### Unary
74+
75+
The simplest case, one request message and one response message.
76+
77+
```javascript
78+
module.exports = function grpcFunction (ipfs, options = {}) {
79+
async function handler (request, metadata) {
80+
const response = {
81+
//... some fields here
82+
}
83+
84+
return response
85+
}
86+
87+
return handler
88+
}
89+
```
90+
91+
### Server streaming
92+
93+
Where the server sends repeated messages. `sink` is an [it-pushable][].
94+
95+
```javascript
96+
module.exports = function grpcFunction (ipfs, options = {}) {
97+
async function serverStreamingHandler (request, sink, metadata) {
98+
sink.push(..)
99+
sink.push(..)
100+
101+
sink.end()
102+
}
103+
104+
return clientStreamingHandler
105+
}
106+
```
107+
108+
### Client streaming
109+
110+
Where the client sends repeated messages. `source` is an [AsyncIterator][].
111+
112+
```javascript
113+
module.exports = function grpcFunction (ipfs, options = {}) {
114+
async function clientStreamingHandler (source, metadata) {
115+
const response = {
116+
//... some fields here
117+
}
118+
119+
for await (const thing of source) {
120+
// do something with `thing`
121+
}
122+
123+
return response
124+
}
125+
126+
return handler
127+
}
128+
```
129+
130+
### Bidirectional streaming
131+
132+
The simplest case, one request message and one response message. `source` is an [AsyncIterator][] and `sink` is an [it-pushable][].
133+
134+
```javascript
135+
module.exports = function grpcFunction (ipfs, options = {}) {
136+
async function bidirectionalHandler (source, sink, metadata) {
137+
for await (const thing of source) {
138+
sink.push(sink)
139+
}
140+
141+
sink.end()
142+
}
143+
144+
return bidirectionalHandler
145+
}
146+
```
147+
148+
[it-pushable]: https://www.npmjs.com/package/it-pushable
149+
[AsyncIterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator

0 commit comments

Comments
 (0)