Integrate async AquaVM into fluence-js (#88)

This commit is contained in:
Pavel 2021-10-20 22:20:43 +03:00 committed by GitHub
parent 727d59fb61
commit fe52648103
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2758 additions and 1739 deletions

File diff suppressed because one or more lines are too long

View File

@ -121,7 +121,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L107">internal/FluencePeer.ts:107</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L132">internal/FluencePeer.ts:132</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -140,13 +140,13 @@
<a name="internals" class="tsd-anchor"></a>
<h3>internals</h3>
<ul class="tsd-signatures tsd-kind-get-signature tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">get</span> internals<span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>callServiceHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">CallServiceHandler</span><span class="tsd-signature-symbol">; </span>initiateFlow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol"> }</span></li>
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">get</span> internals<span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>callServiceHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">CallServiceHandler</span><span class="tsd-signature-symbol">; </span>initiateFlow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>initiateParticle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Particle</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>regHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>common<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>forParticle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>timeout<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol"> }</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L182">internal/FluencePeer.ts:182</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L225">internal/FluencePeer.ts:225</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -154,27 +154,175 @@
<p>Is not intended to be used manually. Subject to change</p>
</div>
</div>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-symbol">{ </span>callServiceHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">CallServiceHandler</span><span class="tsd-signature-symbol">; </span>initiateFlow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol"> }</span></h4>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-symbol">{ </span>callServiceHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">CallServiceHandler</span><span class="tsd-signature-symbol">; </span>initiateFlow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>initiateParticle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Particle</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>regHandler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>common<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>forParticle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>timeout<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol"> }</span></h4>
<ul class="tsd-parameters">
<li class="tsd-parameter">
<h5>call<wbr>Service<wbr>Handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">CallServiceHandler</span></h5>
</li>
<li class="tsd-parameter">
<h5>initiate<wbr>Flow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h5>
<h5>initiate<wbr>Flow<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></li>
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>request<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">RequestFlow</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<div class="tsd-comment tsd-typography">
<dl class="tsd-comment-tags">
<dt>deprecated</dt>
<dd></dd>
</dl>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>request: <span class="tsd-signature-type">RequestFlow</span></h5>
</li>
</ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
<li class="tsd-parameter">
<h5>initiate<wbr>Particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Particle</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Particle</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Initiates a new particle execution starting from local peer</p>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>particle: <span class="tsd-signature-type">Particle</span></h5>
<div class="tsd-comment tsd-typography">
<p>particle to start execution of</p>
</div>
</li>
</ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
<li class="tsd-parameter">
<h5>reg<wbr>Handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">{ </span>common<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>forParticle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">; </span>timeout<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol"> }</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter">
<h5>common<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Register handler for all particles</p>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>serviceId: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>fnName: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>handler: <span class="tsd-signature-type">GenericCallServiceHandler</span></h5>
</li>
</ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
<li class="tsd-parameter">
<h5>for<wbr>Particle<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, serviceId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, fnName<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">GenericCallServiceHandler</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Register handler which will be called only for particle with the specific id</p>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>particleId: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>serviceId: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>fnName: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>handler: <span class="tsd-signature-type">GenericCallServiceHandler</span></h5>
</li>
</ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
<li class="tsd-parameter">
<h5>timeout<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>particleId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, handler<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Register handler which will be called upon particle timeout</p>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>particleId: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>handler: <span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></h5>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
</li>
</ul>
</li>
</ul>
</li>
@ -197,7 +345,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L125">internal/FluencePeer.ts:125</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L150">internal/FluencePeer.ts:150</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -219,7 +367,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L144">internal/FluencePeer.ts:144</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L165">internal/FluencePeer.ts:165</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -251,12 +399,12 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L172">internal/FluencePeer.ts:172</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L209">internal/FluencePeer.ts:209</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Uninitializes the peer: stops all the underltying workflows, stops the Aqua VM
<p>Un-initializes the peer: stops all the underlying workflows, stops the Aqua VM
and disconnects from the Fluence network</p>
</div>
</div>
@ -274,7 +422,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L114">internal/FluencePeer.ts:114</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L139">internal/FluencePeer.ts:139</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">

View File

@ -112,7 +112,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/KeyPair.ts#L27">internal/KeyPair.ts:27</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/KeyPair.ts#L26">internal/KeyPair.ts:26</a></li>
</ul>
</aside>
<h4 class="tsd-parameters-title">Parameters</h4>
@ -134,7 +134,7 @@
<div class="tsd-signature tsd-kind-icon">Libp2p<wbr>Peer<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">PeerId</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/KeyPair.ts#L25">internal/KeyPair.ts:25</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/KeyPair.ts#L24">internal/KeyPair.ts:24</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -156,7 +156,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/KeyPair.ts#L55">internal/KeyPair.ts:55</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/KeyPair.ts#L54">internal/KeyPair.ts:54</a></li>
</ul>
</aside>
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Uint8Array</span></h4>
@ -174,7 +174,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/KeyPair.ts#L36">internal/KeyPair.ts:36</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/KeyPair.ts#L35">internal/KeyPair.ts:35</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -205,7 +205,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/KeyPair.ts#L47">internal/KeyPair.ts:47</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/KeyPair.ts#L46">internal/KeyPair.ts:46</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">

View File

@ -103,7 +103,7 @@
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#particleId" class="tsd-kind-icon">particle<wbr>Id</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#signature" class="tsd-kind-icon">signature</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#tetraplets" class="tsd-kind-icon">tetraplets</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#timeStamp" class="tsd-kind-icon">time<wbr>Stamp</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#timestamp" class="tsd-kind-icon">timestamp</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="CallParams.html#ttl" class="tsd-kind-icon">ttl</a></li>
</ul>
</section>
@ -118,7 +118,7 @@
<div class="tsd-signature tsd-kind-icon">init<wbr>Peer<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L37">internal/commonTypes.ts:37</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L37">internal/commonTypes.ts:37</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -133,7 +133,7 @@
<div class="tsd-signature tsd-kind-icon">particle<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L32">internal/commonTypes.ts:32</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L32">internal/commonTypes.ts:32</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -148,7 +148,7 @@
<div class="tsd-signature tsd-kind-icon">signature<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L52">internal/commonTypes.ts:52</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L52">internal/commonTypes.ts:52</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -163,7 +163,7 @@
<div class="tsd-signature tsd-kind-icon">tetraplets<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{</span><span class="tsd-signature-symbol">[ </span><span class="tsd-signature-type">key</span><span class="tsd-signature-symbol"> in </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">]</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">SecurityTetraplet</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol"> }</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L57">internal/commonTypes.ts:57</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L57">internal/commonTypes.ts:57</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -173,12 +173,12 @@
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-interface">
<a name="timeStamp" class="tsd-anchor"></a>
<h3>time<wbr>Stamp</h3>
<div class="tsd-signature tsd-kind-icon">time<wbr>Stamp<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span></div>
<a name="timestamp" class="tsd-anchor"></a>
<h3>timestamp</h3>
<div class="tsd-signature tsd-kind-icon">timestamp<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L42">internal/commonTypes.ts:42</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L42">internal/commonTypes.ts:42</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -193,7 +193,7 @@
<div class="tsd-signature tsd-kind-icon">ttl<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L47">internal/commonTypes.ts:47</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L47">internal/commonTypes.ts:47</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -238,7 +238,7 @@
<a href="CallParams.html#tetraplets" class="tsd-kind-icon">tetraplets</a>
</li>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="CallParams.html#timeStamp" class="tsd-kind-icon">time<wbr>Stamp</a>
<a href="CallParams.html#timestamp" class="tsd-kind-icon">timestamp</a>
</li>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="CallParams.html#ttl" class="tsd-kind-icon">ttl</a>

View File

@ -104,7 +104,7 @@
<div class="tsd-signature tsd-kind-icon">is<wbr>Connected<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Boolean</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L86">internal/FluencePeer.ts:86</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L111">internal/FluencePeer.ts:111</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -119,7 +119,7 @@
<div class="tsd-signature tsd-kind-icon">is<wbr>Initialized<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Boolean</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L81">internal/FluencePeer.ts:81</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L106">internal/FluencePeer.ts:106</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -134,7 +134,7 @@
<div class="tsd-signature tsd-kind-icon">peer<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L91">internal/FluencePeer.ts:91</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L116">internal/FluencePeer.ts:116</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -149,7 +149,7 @@
<div class="tsd-signature tsd-kind-icon">relay<wbr>Peer<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L96">internal/FluencePeer.ts:96</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L121">internal/FluencePeer.ts:121</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">

View File

@ -105,7 +105,7 @@
<div class="tsd-signature tsd-kind-icon">Avm<wbr>Loglevel<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">LogLevel</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/FluencePeer.ts#L27">internal/FluencePeer.ts:27</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/FluencePeer.ts#L50">internal/FluencePeer.ts:50</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -121,7 +121,7 @@
<div class="tsd-signature tsd-kind-icon">Peer<wbr>IdB58<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/internal/commonTypes.ts#L22">internal/commonTypes.ts:22</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/internal/commonTypes.ts#L22">internal/commonTypes.ts:22</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -139,7 +139,7 @@
<div class="tsd-signature tsd-kind-icon">Fluence<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{ </span>getPeer<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><a href="classes/FluencePeer.html" class="tsd-signature-type" data-tsd-kind="Class">FluencePeer</a><span class="tsd-signature-symbol">; </span>getStatus<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><a href="interfaces/PeerStatus.html" class="tsd-signature-type" data-tsd-kind="Interface">PeerStatus</a><span class="tsd-signature-symbol">; </span>start<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span>config<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">PeerConfig</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol">; </span>stop<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol"> = ...</span></div>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/index.ts#L36">index.ts:36</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/index.ts#L36">index.ts:36</a></li>
</ul>
</aside>
<div class="tsd-comment tsd-typography">
@ -259,7 +259,7 @@
<li class="tsd-description">
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/c0acd41/src/index.ts#L25">index.ts:25</a></li>
<li>Defined in <a href="https://github.com/fluencelabs/fluence-js/blob/9f81458/src/index.ts#L25">index.ts:25</a></li>
</ul>
</aside>
<h4 class="tsd-parameters-title">Parameters</h4>

352
package-lock.json generated
View File

@ -10,7 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.14.4",
"@fluencelabs/avm": "0.15.4",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",
@ -24,6 +24,8 @@
"loglevel": "1.7.0",
"multiaddr": "10.0.0",
"peer-id": "0.15.3",
"rxjs": "^7.3.0",
"ts-pattern": "^3.3.3",
"uuid": "8.3.0"
},
"devDependencies": {
@ -617,16 +619,6 @@
"uint8arrays": "^2.0.5"
}
},
"node_modules/@chainsafe/libp2p-noise/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/@chainsafe/libp2p-noise/node_modules/it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -654,9 +646,9 @@
}
},
"node_modules/@fluencelabs/avm": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.4.tgz",
"integrity": "sha512-XyR+1H5k0CAc+mDHOkl81viX8XeW1Yqbw793xbsfUfju5bUb/hqk+gHv3q8lAFdbrCG5P45gdOT08a5RNODZaQ==",
"version": "0.15.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.15.4.tgz",
"integrity": "sha512-NLZDq83ocJ1Helm0D8kPMSSkjxH0y+Tujg0px773zjIShbh3jgiJOjAW1xCYgTt9K0LqepjP0bWX4/8nUZfr7g==",
"dependencies": {
"base64-js": "1.5.1"
}
@ -1796,6 +1788,16 @@
"file-uri-to-path": "1.0.0"
}
},
"node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
@ -1834,14 +1836,14 @@
"dev": true
},
"node_modules/browserslist": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
"version": "4.16.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz",
"integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==",
"dev": true,
"dependencies": {
"caniuse-lite": "^1.0.30001254",
"caniuse-lite": "^1.0.30001251",
"colorette": "^1.3.0",
"electron-to-chromium": "^1.3.830",
"electron-to-chromium": "^1.3.811",
"escalade": "^3.1.1",
"node-releases": "^1.1.75"
},
@ -1953,9 +1955,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001255",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001255.tgz",
"integrity": "sha512-F+A3N9jTZL882f/fg/WWVnKSu6IOo3ueLz4zwaOPbPYHNmM/ZaDUyzyJwS1mZhX7Ex5jqTyW599Gdelh5PDYLQ==",
"version": "1.0.30001252",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz",
"integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==",
"dev": true,
"funding": {
"type": "opencollective",
@ -2155,9 +2157,9 @@
"dev": true
},
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz",
"integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==",
"dev": true
},
"node_modules/combined-stream": {
@ -2468,9 +2470,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.3.832",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.832.tgz",
"integrity": "sha512-x7lO8tGoW0CyV53qON4Lb5Rok9ipDelNdBIAiYUZ03dqy4u9vohMM1qV047+s/hiyJiqUWX/3PNwkX3kexX5ig==",
"version": "1.3.822",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz",
"integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==",
"dev": true
},
"node_modules/elliptic": {
@ -3477,54 +3479,6 @@
"stream-to-it": "^0.2.2"
}
},
"node_modules/ipfs-utils/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/ipfs-utils/node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/ipfs-utils/node_modules/node-fetch": {
"name": "@achingbrain/node-fetch",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g=="
},
"node_modules/is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@ -3921,16 +3875,6 @@
"buffer": "^6.0.3"
}
},
"node_modules/it-buffer/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/it-drain": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/it-drain/-/it-drain-1.0.4.tgz",
@ -4085,16 +4029,6 @@
"bl": "^5.0.0"
}
},
"node_modules/it-reader/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/it-take": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/it-take/-/it-take-1.0.1.tgz",
@ -5048,16 +4982,6 @@
"uint8arrays": "^3.0.0"
}
},
"node_modules/libp2p-interfaces/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/libp2p-interfaces/node_modules/it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -5091,16 +5015,6 @@
"varint": "^6.0.0"
}
},
"node_modules/libp2p-mplex/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/libp2p-utils": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/libp2p-utils/-/libp2p-utils-0.4.1.tgz",
@ -5134,16 +5048,6 @@
"p-timeout": "^4.1.0"
}
},
"node_modules/libp2p/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/libp2p/node_modules/it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -5560,16 +5464,6 @@
"uint8arrays": "^3.0.0"
}
},
"node_modules/multistream-select/node_modules/bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"dependencies": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/multistream-select/node_modules/it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -5682,6 +5576,12 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node_modules/node-fetch": {
"name": "@achingbrain/node-fetch",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g=="
},
"node_modules/node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -6614,6 +6514,14 @@
"node": "6.* || >= 7.*"
}
},
"node_modules/rxjs": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.3.0.tgz",
"integrity": "sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw==",
"dependencies": {
"tslib": "~2.1.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -7725,6 +7633,16 @@
"node": ">=10"
}
},
"node_modules/ts-pattern": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-3.3.3.tgz",
"integrity": "sha512-Z5EFi6g6wyX3uDFHqxF5W5c5h663oZg9O6aOiAT7fqNu0HPSfCxtHzrQ7SblTy738Mrg2Ezorky8H5aUOm8Pvg=="
},
"node_modules/tslib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -8748,16 +8666,6 @@
"uint8arrays": "^2.0.5"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -8781,9 +8689,9 @@
}
},
"@fluencelabs/avm": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.4.tgz",
"integrity": "sha512-XyR+1H5k0CAc+mDHOkl81viX8XeW1Yqbw793xbsfUfju5bUb/hqk+gHv3q8lAFdbrCG5P45gdOT08a5RNODZaQ==",
"version": "0.15.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.15.4.tgz",
"integrity": "sha512-NLZDq83ocJ1Helm0D8kPMSSkjxH0y+Tujg0px773zjIShbh3jgiJOjAW1xCYgTt9K0LqepjP0bWX4/8nUZfr7g==",
"requires": {
"base64-js": "1.5.1"
}
@ -9752,6 +9660,16 @@
"file-uri-to-path": "1.0.0"
}
},
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
@ -9787,14 +9705,14 @@
"dev": true
},
"browserslist": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
"version": "4.16.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz",
"integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001254",
"caniuse-lite": "^1.0.30001251",
"colorette": "^1.3.0",
"electron-to-chromium": "^1.3.830",
"electron-to-chromium": "^1.3.811",
"escalade": "^3.1.1",
"node-releases": "^1.1.75"
}
@ -9870,9 +9788,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001255",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001255.tgz",
"integrity": "sha512-F+A3N9jTZL882f/fg/WWVnKSu6IOo3ueLz4zwaOPbPYHNmM/ZaDUyzyJwS1mZhX7Ex5jqTyW599Gdelh5PDYLQ==",
"version": "1.0.30001252",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz",
"integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==",
"dev": true
},
"capture-exit": {
@ -10022,9 +9940,9 @@
"dev": true
},
"colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz",
"integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==",
"dev": true
},
"combined-stream": {
@ -10275,9 +10193,9 @@
}
},
"electron-to-chromium": {
"version": "1.3.832",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.832.tgz",
"integrity": "sha512-x7lO8tGoW0CyV53qON4Lb5Rok9ipDelNdBIAiYUZ03dqy4u9vohMM1qV047+s/hiyJiqUWX/3PNwkX3kexX5ig==",
"version": "1.3.822",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz",
"integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==",
"dev": true
},
"elliptic": {
@ -11069,26 +10987,6 @@
"node-fetch": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"react-native-fetch-api": "^2.0.0",
"stream-to-it": "^0.2.2"
},
"dependencies": {
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"node-fetch": {
"version": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g=="
}
}
},
"is-accessor-descriptor": {
@ -11384,18 +11282,6 @@
"requires": {
"bl": "^5.0.0",
"buffer": "^6.0.3"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
}
}
},
"it-drain": {
@ -11540,18 +11426,6 @@
"integrity": "sha512-NxR40odATeaBmSefn6Xn43DplYvn2KtEKQzn4jrTRuPYXMky5M4e+KQ7aTJh0k0vkytLyeenGO1I1GXlGm4laQ==",
"requires": {
"bl": "^5.0.0"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
}
}
},
"it-take": {
@ -12281,16 +12155,6 @@
"xsalsa20": "^1.1.0"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -12351,16 +12215,6 @@
"uint8arrays": "^3.0.0"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -12394,18 +12248,6 @@
"it-pipe": "^1.1.0",
"it-pushable": "^1.4.1",
"varint": "^6.0.0"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
}
}
},
"libp2p-utils": {
@ -12750,16 +12592,6 @@
"uint8arrays": "^3.0.0"
},
"dependencies": {
"bl": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
"integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==",
"requires": {
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"it-length-prefixed": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-5.0.3.tgz",
@ -12854,6 +12686,10 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node-fetch": {
"version": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g=="
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -13565,6 +13401,14 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
"dev": true
},
"rxjs": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.3.0.tgz",
"integrity": "sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw==",
"requires": {
"tslib": "~2.1.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -14464,6 +14308,16 @@
}
}
},
"ts-pattern": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-3.3.3.tgz",
"integrity": "sha512-Z5EFi6g6wyX3uDFHqxF5W5c5h663oZg9O6aOiAT7fqNu0HPSfCxtHzrQ7SblTy738Mrg2Ezorky8H5aUOm8Pvg=="
},
"tslib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",

View File

@ -21,7 +21,7 @@
"license": "Apache-2.0",
"dependencies": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.14.4",
"@fluencelabs/avm": "0.15.4",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",
@ -35,6 +35,8 @@
"loglevel": "1.7.0",
"multiaddr": "10.0.0",
"peer-id": "0.15.3",
"rxjs": "^7.3.0",
"ts-pattern": "^3.3.3",
"uuid": "8.3.0"
},
"devDependencies": {

File diff suppressed because one or more lines are too long

View File

@ -1,25 +1,48 @@
import { Fluence, FluencePeer } from '../../index';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
const anotherPeer = new FluencePeer();
import { FluencePeer } from '../../index';
import { Particle } from '../../internal/Particle';
import { registerHandlersHelper } from '../util';
describe('Avm spec', () => {
afterEach(async () => {
if (anotherPeer) {
await anotherPeer.stop();
}
it('Simple call', async () => {
// arrange
const peer = new FluencePeer();
await peer.start();
// act
const promise = new Promise<string[]>((resolve, reject) => {
const script = `
(call %init_peer_id% ("print" "print") ["1"])
`;
const particle = Particle.createNew(script);
registerHandlersHelper(peer, particle, {
print: {
print: async (args) => {
const [res] = args;
resolve(res);
},
},
_timeout: reject,
});
peer.internals.initiateParticle(particle);
});
// assert
const res = await promise;
expect(res).toBe('1');
await peer.stop();
});
it('Par execution should work', async () => {
it('Par call', async () => {
// arrange
await Fluence.start();
const peer = new FluencePeer();
await peer.start();
let request;
const promise = new Promise<string[]>((resolve) => {
// act
const promise = new Promise<string[]>((resolve, reject) => {
let res = [];
request = new RequestFlowBuilder()
.withRawScript(
`
const script = `
(seq
(par
(call %init_peer_id% ("print" "print") ["1"])
@ -27,24 +50,27 @@ describe('Avm spec', () => {
)
(call %init_peer_id% ("print" "print") ["2"])
)
`,
)
.configHandler((h) => {
h.onEvent('print', 'print', async (args) => {
`;
const particle = Particle.createNew(script);
registerHandlersHelper(peer, particle, {
print: {
print: (args) => {
res.push(args[0]);
if (res.length == 2) {
resolve(res);
}
});
})
.build();
},
},
_timeout: reject,
});
peer.internals.initiateParticle(particle);
});
// act
await Fluence.getPeer().internals.initiateFlow(request);
const res = await promise;
// assert
const res = await promise;
expect(res).toStrictEqual(['1', '2']);
await peer.stop();
});
});

View File

@ -1,5 +1,6 @@
import { Fluence, FluencePeer } from '../../..';
import { RequestFlowBuilder } from '../../../internal/RequestFlowBuilder';
import { Particle } from '../../../internal/Particle';
import { registerHandlersHelper } from '../../util';
import { callMeBack, registerHelloWorld } from './gen1';
describe('Compiler support infrastructure tests', () => {
@ -50,7 +51,7 @@ describe('Compiler support infrastructure tests', () => {
const helloPromise = new Promise((resolve) => {
registerHelloWorld('hello_world', {
sayHello: (s, params) => {
const tetrapelt = params.tetraplets.s; // completion should work here
const tetraplet = params.tetraplets.s; // completion should work here
resolve(s);
},
getNumber: (params) => {
@ -60,23 +61,32 @@ describe('Compiler support infrastructure tests', () => {
});
});
const [request, getNumberPromise] = new RequestFlowBuilder()
.withRawScript(
`(seq
(seq
(call %init_peer_id% ("hello_world" "sayHello") ["hello world!"])
(call %init_peer_id% ("hello_world" "getNumber") [] result)
)
(call %init_peer_id% ("callback" "callback") [result])
)`,
)
.buildAsFetch<[string]>('callback', 'callback');
await Fluence.getPeer().internals.initiateFlow(request);
const getNumberPromise = new Promise<string>((resolve, reject) => {
const script = `
(seq
(seq
(call %init_peer_id% ("hello_world" "sayHello") ["hello world!"])
(call %init_peer_id% ("hello_world" "getNumber") [] result)
)
(call %init_peer_id% ("callback" "callback") [result])
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(Fluence.getPeer(), particle, {
callback: {
callback: (args) => {
const [val] = args;
resolve(val);
},
},
_timeout: reject,
});
Fluence.getPeer().internals.initiateParticle(particle);
});
// assert
expect(await helloPromise).toBe('hello world!');
expect(await getNumberPromise).toStrictEqual([42]);
expect(await getNumberPromise).toBe(42);
await Fluence.stop();
});
@ -122,14 +132,14 @@ describe('Compiler support infrastructure tests', () => {
it('Compiled code for service should work another peer', async () => {
// arrange
const peer = new FluencePeer();
await peer.start();
const anotherPeer = new FluencePeer();
await anotherPeer.start();
// act
const helloPromise = new Promise((resolve) => {
registerHelloWorld(peer, 'hello_world', {
registerHelloWorld(anotherPeer, 'hello_world', {
sayHello: (s, params) => {
const tetrapelt = params.tetraplets.s; // completion should work here
const tetraplet = params.tetraplets.s; // completion should work here
resolve(s);
},
getNumber: (params) => {
@ -139,23 +149,32 @@ describe('Compiler support infrastructure tests', () => {
});
});
const [request, getNumberPromise] = new RequestFlowBuilder()
.withRawScript(
`(seq
(seq
(call %init_peer_id% ("hello_world" "sayHello") ["hello world!"])
(call %init_peer_id% ("hello_world" "getNumber") [] result)
)
(call %init_peer_id% ("callback" "callback") [result])
)`,
)
.buildAsFetch<[string]>('callback', 'callback');
await peer.internals.initiateFlow(request);
const getNumberPromise = new Promise<string>((resolve, reject) => {
const script = `
(seq
(seq
(call %init_peer_id% ("hello_world" "sayHello") ["hello world!"])
(call %init_peer_id% ("hello_world" "getNumber") [] result)
)
(call %init_peer_id% ("callback" "callback") [result])
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(anotherPeer, particle, {
callback: {
callback: (args) => {
const [val] = args;
resolve(val);
},
},
_timeout: reject,
});
anotherPeer.internals.initiateParticle(particle);
});
// assert
expect(await helloPromise).toBe('hello world!');
expect(await getNumberPromise).toStrictEqual([42]);
expect(await getNumberPromise).toBe(42);
await peer.stop();
await anotherPeer.stop();
});
});

View File

@ -19,10 +19,14 @@ func callMeBack(callback: string, i32 -> ()):
* This file is auto-generated. Do not edit manually: changes may be erased.
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* Aqua version: 0.2.2-SNAPSHOT
* Aqua version: 0.3.1-231
*
*/
function missingFields(obj: any, fields: string[]): string[] {
return fields.filter((f) => !(f in obj));
}
// Services
export interface HelloWorldDef {
@ -34,11 +38,11 @@ export function registerHelloWorld(service: HelloWorldDef): void;
export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void;
export function registerHelloWorld(peer: FluencePeer, service: HelloWorldDef): void;
export function registerHelloWorld(peer: FluencePeer, serviceId: string, service: HelloWorldDef): void;
export function registerHelloWorld(...args) {
export function registerHelloWorld(...args: any) {
let peer: FluencePeer;
let serviceId;
let service;
if (args[0] instanceof FluencePeer) {
let serviceId: any;
let service: any;
if (FluencePeer.isInstance(args[0])) {
peer = args[0];
} else {
peer = Fluence.getPeer();
@ -52,7 +56,12 @@ export function registerHelloWorld(...args) {
serviceId = 'default';
}
if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') {
// Figuring out which overload is the service.
// If the first argument is not Fluence Peer and it is an object, then it can only be the service def
// If the first argument is peer, we are checking further. The second argument might either be
// an object, that it must be the service object
// or a string, which is the service id. In that case the service is the third argument
if (!FluencePeer.isInstance(args[0]) && typeof args[0] === 'object') {
service = args[0];
} else if (typeof args[1] === 'object') {
service = args[1];
@ -60,6 +69,14 @@ export function registerHelloWorld(...args) {
service = args[2];
}
const incorrectServiceDefinitions = missingFields(service, ['getNumber', 'sayHello']);
if (!!incorrectServiceDefinitions.length) {
throw new Error(
'Error registering service HelloWorld: missing functions: ' +
incorrectServiceDefinitions.map((d) => "'" + d + "'").join(', '),
);
}
peer.internals.callServiceHandler.use((req, resp, next) => {
if (req.serviceId !== serviceId) {
next();
@ -102,11 +119,11 @@ export function callMeBack(
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<void>;
export function callMeBack(...args) {
export function callMeBack(...args: any) {
let peer: FluencePeer;
let callback;
let config;
if (args[0] instanceof FluencePeer) {
let callback: any;
let config: any;
if (FluencePeer.isInstance(args[0])) {
peer = args[0];
callback = args[1];
config = args[2];
@ -122,24 +139,22 @@ export function callMeBack(...args) {
.disableInjections()
.withRawScript(
`
(xor
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
`,
(xor
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
`,
)
.configHandler((h) => {
h.on('getDataSrv', '-relay-', () => {
return peer.getStatus().relayPeerId || null;
return peer.getStatus().relayPeerId;
});
h.use((req, resp, next) => {
if (req.serviceId === 'callbackSrv' && req.fnName === 'callback') {
const callParams = {
@ -157,7 +172,6 @@ export function callMeBack(...args) {
});
h.onEvent('callbackSrv', 'response', (args) => {});
h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args;
reject(err);
@ -167,9 +181,11 @@ export function callMeBack(...args) {
.handleTimeout(() => {
reject('Request timed out for callMeBack');
});
if (config && config.ttl) {
r.withTTL(config.ttl);
}
request = r.build();
});
peer.internals.initiateFlow(request!);

View File

@ -0,0 +1,519 @@
import { CallParams, registerService, callFunction } from '../../../internal/compilerSupport/v2';
import { FluencePeer } from '../../../index';
/*
-- file to generate functions below from
service ServiceWithDefaultId("defaultId"):
hello(s: string)
service ServiceWithOUTDefaultId:
hello(s: string)
service MoreMembers:
member1()
member2(s1: string)
member3(s1: string, s2: string)
member4(s1: string, s2: string, i: i32) -> i32
member5(s1: string, s2: string, i: i32) -> i32
func f1(callback: string, i32 -> ()):
callback("hello, world", 42)
func f2(num: i32, callback: string, i32 -> ()):
callback("hello, world", 42)
func f3(num: i32, callback: string, i32 -> ()) -> string:
callback("hello, world", 42)
<- "hello world"
func callBackZeroArgs(callback: -> ()):
callback()
*/
/**
*
* This file is auto-generated. Do not edit manually: changes may be erased.
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* Aqua version: 0.3.1-231
*
*/
// Services
export interface ServiceWithDefaultIdDef {
hello: (s: string, callParams: CallParams<'s'>) => void;
}
export function registerServiceWithDefaultId(service: ServiceWithDefaultIdDef): void;
export function registerServiceWithDefaultId(serviceId: string, service: ServiceWithDefaultIdDef): void;
export function registerServiceWithDefaultId(peer: FluencePeer, service: ServiceWithDefaultIdDef): void;
export function registerServiceWithDefaultId(
peer: FluencePeer,
serviceId: string,
service: ServiceWithDefaultIdDef,
): void;
export function registerServiceWithDefaultId(...args: any) {
registerService(args, {
defaultServiceId: 'defaultId',
functions: [
{
functionName: 'hello',
argDefs: [
{
name: 's',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
],
});
}
export interface ServiceWithOUTDefaultIdDef {
hello: (s: string, callParams: CallParams<'s'>) => void;
}
export function registerServiceWithOUTDefaultId(serviceId: string, service: ServiceWithOUTDefaultIdDef): void;
export function registerServiceWithOUTDefaultId(
peer: FluencePeer,
serviceId: string,
service: ServiceWithOUTDefaultIdDef,
): void;
export function registerServiceWithOUTDefaultId(...args: any) {
registerService(args, {
defaultServiceId: null,
functions: [
{
functionName: 'hello',
argDefs: [
{
name: 's',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
],
});
}
export interface MoreMembersDef {
member1: (callParams: CallParams<null>) => void;
member2: (s1: string, callParams: CallParams<'s1'>) => void;
member3: (s1: string, s2: string, callParams: CallParams<'s1' | 's2'>) => void;
member4: (s1: string, s2: string, i: number, callParams: CallParams<'s1' | 's2' | 'i'>) => number;
member5: (s1: string, s2: string, i: number, callParams: CallParams<'s1' | 's2' | 'i'>) => number;
}
export function registerMoreMembers(serviceId: string, service: MoreMembersDef): void;
export function registerMoreMembers(peer: FluencePeer, serviceId: string, service: MoreMembersDef): void;
export function registerMoreMembers(...args: any) {
registerService(args, {
defaultServiceId: null,
functions: [
{
functionName: 'member1',
argDefs: [],
returnType: {
tag: 'void',
},
},
{
functionName: 'member2',
argDefs: [
{
name: 's1',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
{
functionName: 'member3',
argDefs: [
{
name: 's1',
argType: {
tag: 'primitive',
},
},
{
name: 's2',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
{
functionName: 'member4',
argDefs: [
{
name: 's1',
argType: {
tag: 'primitive',
},
},
{
name: 's2',
argType: {
tag: 'primitive',
},
},
{
name: 'i',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'primitive',
},
},
{
functionName: 'member5',
argDefs: [
{
name: 's1',
argType: {
tag: 'primitive',
},
},
{
name: 's2',
argType: {
tag: 'primitive',
},
},
{
name: 'i',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'primitive',
},
},
],
});
}
// Functions
export function f1(
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<void>;
export function f1(
peer: FluencePeer,
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<void>;
export function f1(...args: any) {
let script = `
(xor
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
`;
return callFunction(
args,
{
functionName: 'f1',
returnType: {
tag: 'void',
},
argDefs: [
{
name: 'callback',
argType: {
tag: 'callback',
callback: {
argDefs: [
{
name: 'arg0',
argType: {
tag: 'primitive',
},
},
{
name: 'arg1',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
},
},
],
names: {
relay: '-relay-',
getDataSrv: 'getDataSrv',
callbackSrv: 'callbackSrv',
responseSrv: 'callbackSrv',
responseFnName: 'response',
errorHandlingSrv: 'errorHandlingSrv',
errorFnName: 'error',
},
},
script,
);
}
export function f2(
num: number,
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<void>;
export function f2(
peer: FluencePeer,
num: number,
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<void>;
export function f2(...args: any) {
let script = `
(xor
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "num") [] num)
)
(xor
(call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
`;
return callFunction(
args,
{
functionName: 'f2',
returnType: {
tag: 'void',
},
argDefs: [
{
name: 'num',
argType: {
tag: 'primitive',
},
},
{
name: 'callback',
argType: {
tag: 'callback',
callback: {
argDefs: [
{
name: 'arg0',
argType: {
tag: 'primitive',
},
},
{
name: 'arg1',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
},
},
],
names: {
relay: '-relay-',
getDataSrv: 'getDataSrv',
callbackSrv: 'callbackSrv',
responseSrv: 'callbackSrv',
responseFnName: 'response',
errorHandlingSrv: 'errorHandlingSrv',
errorFnName: 'error',
},
},
script,
);
}
export function f3(
num: number,
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<string>;
export function f3(
peer: FluencePeer,
num: number,
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
config?: { ttl?: number },
): Promise<string>;
export function f3(...args: any) {
let script = `
(xor
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "num") [] num)
)
(xor
(call %init_peer_id% ("callbackSrv" "callback") ["hello, world" 42])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(xor
(call %init_peer_id% ("callbackSrv" "response") ["hello world"])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3])
)
`;
return callFunction(
args,
{
functionName: 'f3',
returnType: {
tag: 'primitive',
},
argDefs: [
{
name: 'num',
argType: {
tag: 'primitive',
},
},
{
name: 'callback',
argType: {
tag: 'callback',
callback: {
argDefs: [
{
name: 'arg0',
argType: {
tag: 'primitive',
},
},
{
name: 'arg1',
argType: {
tag: 'primitive',
},
},
],
returnType: {
tag: 'void',
},
},
},
},
],
names: {
relay: '-relay-',
getDataSrv: 'getDataSrv',
callbackSrv: 'callbackSrv',
responseSrv: 'callbackSrv',
responseFnName: 'response',
errorHandlingSrv: 'errorHandlingSrv',
errorFnName: 'error',
},
},
script,
);
}
export function callBackZeroArgs(
callback: (callParams: CallParams<null>) => void,
config?: { ttl?: number },
): Promise<void>;
export function callBackZeroArgs(
peer: FluencePeer,
callback: (callParams: CallParams<null>) => void,
config?: { ttl?: number },
): Promise<void>;
export function callBackZeroArgs(...args: any) {
let script = `
(xor
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("callbackSrv" "callback") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
`;
return callFunction(
args,
{
functionName: 'callBackZeroArgs',
returnType: {
tag: 'void',
},
argDefs: [
{
name: 'callback',
argType: {
tag: 'callback',
callback: {
argDefs: [],
returnType: {
tag: 'void',
},
},
},
},
],
names: {
relay: '-relay-',
getDataSrv: 'getDataSrv',
callbackSrv: 'callbackSrv',
responseSrv: 'callbackSrv',
responseFnName: 'response',
errorHandlingSrv: 'errorHandlingSrv',
errorFnName: 'error',
},
},
script,
);
}

View File

@ -1,9 +1,9 @@
import { Multiaddr } from 'multiaddr';
import { nodes } from '../connection';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
import log from 'loglevel';
import { Fluence, FluencePeer } from '../../index';
import { Fluence, FluencePeer, setLogLevel } from '../../index';
import { checkConnection } from '../../internal/utils';
import { Particle } from '../../internal/Particle';
import { registerHandlersHelper } from '../util';
const anotherPeer = new FluencePeer();
@ -67,7 +67,7 @@ describe('Typescript usage suite', () => {
});
it('Should expose correct status for connected peer', async () => {
// arrnge
// arrange
const peer = new FluencePeer();
await peer.start({ connectTo: nodes[0] });
@ -89,18 +89,46 @@ describe('Typescript usage suite', () => {
await anotherPeer.start({ connectTo: nodes[0] });
// act
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`(seq
(call init_relay ("op" "identity") ["hello world!"] result)
(call %init_peer_id% ("callback" "callback") [result])
)`,
const promise = new Promise<string[]>((resolve, reject) => {
const script = `
(xor
(seq
(call %init_peer_id% ("load" "relay") [] init_relay)
(seq
(call init_relay ("op" "identity") ["hello world!"] result)
(call %init_peer_id% ("callback" "callback") [result])
)
.buildAsFetch<[string]>('callback', 'callback');
await anotherPeer.internals.initiateFlow(request);
)
(seq
(call init_relay ("op" "identity") [])
(call %init_peer_id% ("callback" "error") [%last_error%])
)
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(anotherPeer, particle, {
load: {
relay: (args) => {
return anotherPeer.getStatus().relayPeerId;
},
},
callback: {
callback: (args) => {
const [val] = args;
resolve(val);
},
error: (args) => {
const [error] = args;
reject(error);
},
},
_timeout: reject,
});
anotherPeer.internals.initiateParticle(particle);
});
// assert
const [result] = await promise;
const result = await promise;
expect(result).toBe('hello world!');
});
@ -127,30 +155,25 @@ describe('Typescript usage suite', () => {
const peer2 = new FluencePeer();
await peer2.start({ connectTo: nodes[0] });
let resMakingPromise = new Promise((resolve) => {
// act
const resMakingPromise = new Promise((resolve) => {
peer2.internals.callServiceHandler.onEvent('test', 'test', (args, _) => {
resolve([...args]);
return {};
resolve(args[0]);
});
});
let script = `
const script = `
(seq
(call "${peer1.getStatus().relayPeerId}" ("op" "identity") [])
(call "${peer2.getStatus().peerId}" ("test" "test") [a b c d])
(call "${peer2.getStatus().peerId}" ("test" "test") ["test"])
)
`;
const particle = Particle.createNew(script);
await peer1.internals.initiateParticle(particle);
let data: Map<string, any> = new Map();
data.set('a', 'some a');
data.set('b', 'some b');
data.set('c', 'some c');
data.set('d', 'some d');
await peer1.internals.initiateFlow(new RequestFlowBuilder().withRawScript(script).withVariables(data).build());
let res = await resMakingPromise;
expect(res).toEqual(['some a', 'some b', 'some c', 'some d']);
// assert
const res = await resMakingPromise;
expect(res).toEqual('test');
await peer1.stop();
await peer2.stop();
@ -254,103 +277,161 @@ describe('Typescript usage suite', () => {
});
});
it('xor handling should work with connected client', async function () {
it('Should successfully call identity on local peer', async function () {
// arrange
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`
(seq
(call init_relay ("op" "identity") [])
(call init_relay ("incorrect" "service") ["incorrect_arg"])
)
`,
)
.buildWithErrorHandling();
await anotherPeer.start();
// act
await anotherPeer.start({ connectTo: nodes[0] });
await anotherPeer.internals.initiateFlow(request);
const promise = new Promise<string>((resolve, reject) => {
const script = `
(seq
(call %init_peer_id% ("op" "identity") ["test"] res)
(call %init_peer_id% ("callback" "callback") [res])
)
`;
const particle = Particle.createNew(script);
registerHandlersHelper(anotherPeer, particle, {
callback: {
callback: async (args) => {
const [res] = args;
resolve(res);
},
},
// op: {
// identity: (req) => {},
// },
_timeout: reject,
});
// assert
await expect(promise).rejects.toMatchObject({
msg: expect.stringContaining("Service with id 'incorrect' not found"),
instruction: expect.stringContaining('incorrect'),
anotherPeer.internals.initiateParticle(particle);
});
});
it('xor handling should work with local client', async function () {
// arrange
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`
(call %init_peer_id% ("service" "fails") [])
`,
)
.configHandler((h) => {
h.use((req, res, _) => {
res.retCode = 1;
res.result = 'service failed internally';
});
})
.buildWithErrorHandling();
// act
await anotherPeer.start();
await anotherPeer.internals.initiateFlow(request);
// assert
await expect(promise).rejects.toMatch('service failed internally');
const res = await promise;
expect(res).toBe('test');
});
it.skip('Should throw correct message when calling non existing local service', async function () {
it('Should throw correct message when calling non existing local service', async function () {
// arrange
await anotherPeer.start();
await anotherPeer.start({ connectTo: nodes[0] });
// act
const res = callIdentifyOnInitPeerId(anotherPeer);
const res = callIncorrectService(anotherPeer);
// assert
await expect(res).rejects.toMatchObject({
msg: expect.stringContaining(
`The handler did not set any result. Make sure you are calling the right peer and the handler has been registered. Original request data was: serviceId='peer' fnName='identify' args=''\"'`,
`No handler has been registered for serviceId='incorrect' fnName='incorrect' args=''\"'`,
),
instruction: 'call %init_peer_id% ("peer" "identify") [] res',
instruction: 'call %init_peer_id% ("incorrect" "incorrect") [] res',
});
});
it('Should not crash if undefined is passed as a variable', async () => {
// arrange
// arrange;
await anotherPeer.start();
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`
(seq
(call %init_peer_id% ("op" "identity") [arg] res)
(call %init_peer_id% ("return" "return") [res])
)
`,
)
.withVariable('arg', undefined as any)
.buildAsFetch<any[]>('return', 'return');
// act
await anotherPeer.internals.initiateFlow(request);
const [res] = await promise;
const promise = new Promise<any>((resolve, reject) => {
const script = `
(seq
(call %init_peer_id% ("load" "arg") [] arg)
(seq
(call %init_peer_id% ("op" "identity") [arg] res)
(call %init_peer_id% ("callback" "callback") [res])
)
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(anotherPeer, particle, {
load: {
arg: (args) => {
return undefined;
},
},
callback: {
callback: (args) => {
const [val] = args;
resolve(val);
},
error: (args) => {
const [error] = args;
reject(error);
},
},
_timeout: reject,
});
anotherPeer.internals.initiateParticle(particle);
});
// assert
const res = await promise;
expect(res).toBe(null);
});
it('Should throw correct error when the client tries to send a particle not to the relay', async () => {
// arrange
it('Should not crash if an error ocurred in user-defined handler', async () => {
// arrange;
setLogLevel('trace');
await anotherPeer.start();
// act
const [req, promise] = new RequestFlowBuilder()
.withRawScript('(call "incorrect_peer_id" ("any" "service") [])')
.buildWithErrorHandling();
const promise = new Promise<any>((resolve, reject) => {
const script = `
(xor
(call %init_peer_id% ("load" "arg") [] arg)
(call %init_peer_id% ("callback" "error") [%last_error%])
)`;
const particle = Particle.createNew(script);
await anotherPeer.internals.initiateFlow(req);
registerHandlersHelper(anotherPeer, particle, {
load: {
arg: (args) => {
throw 'my super custom error message';
},
},
callback: {
error: (args) => {
const [error] = args;
reject(error);
},
},
_timeout: reject,
});
anotherPeer.internals.initiateParticle(particle);
});
// assert
await expect(promise).rejects.toMatchObject({
msg: expect.stringContaining('my super custom error message'),
});
});
it.skip('Should throw correct error when the client tries to send a particle not to the relay', async () => {
// arrange;
await anotherPeer.start({ connectTo: nodes[0] });
// act
const promise = new Promise((resolve, reject) => {
const script = `
(xor
(call "incorrect_peer_id" ("any" "service") [])
(call %init_peer_id% ("callback" "error") [%last_error%])
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(anotherPeer, particle, {
callback: {
error: (args) => {
const [error] = args;
reject(error);
},
},
});
anotherPeer.internals.initiateParticle(particle);
});
// assert
await expect(promise).rejects.toMatch(
@ -359,18 +440,30 @@ describe('Typescript usage suite', () => {
});
});
async function callIdentifyOnInitPeerId(peer: FluencePeer): Promise<string[]> {
let request;
const promise = new Promise<string[]>((resolve, reject) => {
request = new RequestFlowBuilder()
.withRawScript(
`
(call %init_peer_id% ("peer" "identify") [] res)
`,
)
.handleScriptError(reject)
.build();
async function callIncorrectService(peer: FluencePeer): Promise<string[]> {
const promise = new Promise<any[]>((resolve, reject) => {
const script = `
(xor
(call %init_peer_id% ("incorrect" "incorrect") [] res)
(call %init_peer_id% ("callback" "error") [%last_error%])
)`;
const particle = Particle.createNew(script);
registerHandlersHelper(peer, particle, {
callback: {
callback: (args) => {
resolve(args);
},
error: (args) => {
const [error] = args;
reject(error);
},
},
_timeout: reject,
});
peer.internals.initiateParticle(particle);
});
await peer.internals.initiateFlow(request);
return promise;
}

View File

@ -1,5 +1,5 @@
import { CallServiceData, CallServiceHandler, ResultCodes } from '../../internal/CallServiceHandler';
import { errorHandler } from '../../internal/defaultMiddlewares';
import { CallServiceData, ResultCodes } from '../../internal/commonTypes';
import { CallServiceHandler } from '../../internal/compilerSupport/LegacyCallServiceHandler';
const req = (): CallServiceData => ({
serviceId: 'service',
@ -92,25 +92,6 @@ describe('Call service handler tests', () => {
});
});
it('Should work with provided error handling middleware', () => {
// arrange
const handler = new CallServiceHandler();
handler.use(errorHandler);
handler.use((req, res, next) => {
throw new Error('some error');
});
// act
const res = handler.execute(req());
// assert
expect(res).toMatchObject({
retCode: ResultCodes.exceptionInHandler,
result: 'Handler failed. fnName="fn name" serviceId="service" error: Error: some error',
});
});
describe('Service handler tests', () => {
it('Should register service function', () => {
// arrange
@ -134,28 +115,6 @@ describe('Call service handler tests', () => {
});
});
it('Should UNregister service function', () => {
// arrange
const handler = new CallServiceHandler();
const unreg = handler.on('service', 'function', (args) => {
return { called: args };
});
unreg();
// act
const res = handler.execute({
...req(),
serviceId: 'service',
fnName: 'function',
args: ['hello', 'world'],
});
// assert
expect(res).toMatchObject({
retCode: ResultCodes.unkownError,
});
});
it('Should register event', async () => {
// arrange
const handler = new CallServiceHandler();
@ -180,28 +139,6 @@ describe('Call service handler tests', () => {
await expect(returnPromise).resolves.toMatchObject({ called: ['hello', 'world'] });
});
it('Should UNregister event', () => {
// arrange
const handler = new CallServiceHandler();
const unreg = handler.onEvent('service', 'function', (args) => {
// don't care
});
unreg();
// act
const res = handler.execute({
...req(),
serviceId: 'service',
fnName: 'function',
args: ['hello', 'world'],
});
// assert
expect(res).toMatchObject({
retCode: ResultCodes.unkownError,
});
});
it('Should register multiple service functions', () => {
// arrange
const handler = new CallServiceHandler();

View File

@ -1,31 +0,0 @@
import { KeyPair } from '../../internal/KeyPair';
import { RequestFlow } from '../../internal/RequestFlow';
import * as base64 from 'base64-js';
describe('Request flow tests', () => {
it('particle initiation should work', async () => {
// arrange
jest.useFakeTimers();
const sk = 'z1x3cVXhk9nJKE1pZaX9KxccUBzxu3aGlaUjDdAB2oY=';
const skBytes = base64.toByteArray(sk);
const mockDate = new Date(Date.UTC(2021, 2, 14)).valueOf();
Date.now = jest.fn(() => mockDate);
const request = RequestFlow.createLocal('(null)', 10000);
const peerId = await (await KeyPair.fromEd25519SK(skBytes)).Libp2pPeerId;
// act
await request.initState(peerId);
// assert
const particle = request.getParticle();
expect(particle).toMatchObject({
init_peer_id: peerId.toB58String(),
script: '(null)',
signature: '',
timestamp: mockDate,
ttl: 10000,
});
expect(setTimeout).toHaveBeenCalledTimes(1);
});
});

View File

@ -1,24 +0,0 @@
import { FluenceConnection } from '../../internal/FluenceConnection';
import Peer from 'libp2p';
import { Multiaddr } from 'multiaddr';
import { KeyPair } from '../../internal/KeyPair';
describe('Ws Transport', () => {
// TODO:: fix test
test.skip('Should work with ws schema', async () => {
// arrange
let multiaddr = new Multiaddr(
'/ip4/127.0.0.1/tcp/1234/ws/p2p/12D3KooWMJ78GJrtCxVUpjLEedbPtnLDxkFQJ2wuefEdrxq6zwSs',
);
let peerId = (await KeyPair.randomEd25519()).Libp2pPeerId;
const connection = new FluenceConnection(multiaddr, peerId, peerId, (_) => {});
await (connection as any).createPeer();
let node = (connection as any).node as Peer;
// act
let transport = node.transportManager.transportForMultiaddr(multiaddr);
// assert
expect(transport).toBeDefined();
});
});

View File

@ -1,6 +1,6 @@
import each from 'jest-each';
import { CallServiceData } from '../../internal/CallServiceHandler';
import makeDefaultClientHandler from '../../internal/defaultClientHandler';
import { CallServiceData } from '../../internal/commonTypes';
import { defaultServices } from '../../internal/defaultServices';
describe('Tests for default handler', () => {
// prettier-ignore
@ -34,7 +34,7 @@ describe('Tests for default handler', () => {
`.test(
//
'$fnName with $args expected retcode: $retCode and result: $result',
({ fnName, args, retCode, result }) => {
async ({ fnName, args, retCode, result }) => {
// arrange
const req: CallServiceData = {
serviceId: 'op',
@ -51,14 +51,41 @@ describe('Tests for default handler', () => {
};
// act
const res = makeDefaultClientHandler().execute(req);
const fn = defaultServices[req.serviceId][req.fnName];
const res = await fn(req);
// assert
expect(res).toMatchObject({
retCode: retCode,
result: result,
});
const handler = makeDefaultClientHandler();
},
);
it('should return correct error message for identiy service', async () => {
// arrange
const req: CallServiceData = {
serviceId: 'peer',
fnName: 'identify',
args: [],
tetraplets: [],
particleContext: {
particleId: 'some',
initPeerId: 'init peer id',
timestamp: 595951200,
ttl: 595961200,
signature: 'sig',
},
};
// act
const fn = defaultServices[req.serviceId][req.fnName];
const res = await fn(req);
// assert
expect(res).toMatchObject({
retCode: 1,
result: 'The JS implementation of Peer does not support identify',
});
});
});

17
src/__test__/util.ts Normal file
View File

@ -0,0 +1,17 @@
import { FluencePeer } from '../index';
import { Particle } from '../internal/Particle';
import { MakeServiceCall } from '../internal/utils';
export const registerHandlersHelper = (peer: FluencePeer, particle: Particle, handlers) => {
const { _timeout, ...rest } = handlers;
if (_timeout) {
peer.internals.regHandler.timeout(particle.id, _timeout);
}
for (let serviceId in rest) {
for (let fnName in rest[serviceId]) {
// of type [args] => result
const h = rest[serviceId][fnName];
peer.internals.regHandler.forParticle(particle.id, serviceId, fnName, MakeServiceCall(h));
}
}
};

View File

@ -16,82 +16,53 @@
import Websockets from 'libp2p-websockets';
import Mplex from 'libp2p-mplex';
import Peer from 'libp2p';
import Lib2p2Peer from 'libp2p';
import { decode, encode } from 'it-length-prefixed';
import pipe from 'it-pipe';
import * as log from 'loglevel';
import { logParticle, parseParticle, Particle, toPayload } from './particle';
import { Particle } from './Particle';
import { NOISE } from '@chainsafe/libp2p-noise';
import PeerId from 'peer-id';
import { Multiaddr } from 'multiaddr';
import { all as allow_all } from 'libp2p-websockets/src/filters';
import { Connection } from 'libp2p-interfaces/src/topology';
export const PROTOCOL_NAME = '/fluence/particle/2.0.0';
enum Status {
Initializing = 'Initializing',
Connected = 'Connected',
Disconnected = 'Disconnected',
}
/**
* Options to configure fluence connection
*/
export interface FluenceConnectionOptions {
/**
* @property {number} [checkConnectionTTL] - TTL for the check connection request in ms
* Peer id of the Fluence Peer
*/
checkConnectionTTL?: number;
peerId: PeerId;
/**
* @property {number} [checkConnectionTTL] - set to true to skip check connection request completely
* Multiaddress of the relay to make connection to
*/
skipCheckConnection?: boolean;
relayAddress: Multiaddr;
/**
* @property {number} [dialTimeout] - How long a dial attempt is allowed to take.
* The dialing timeout in milliseconds
*/
dialTimeout?: number;
dialTimeoutMs?: number;
/**
* Handler for incoming particles from the connection
*/
onIncomingParticle: (p: Particle) => void;
}
export class FluenceConnection {
private readonly selfPeerId: PeerId;
private node: Peer;
private readonly address: Multiaddr;
readonly nodePeerId: PeerId;
private readonly selfPeerIdStr: string;
private readonly handleParticle: (call: Particle) => void;
constructor() {}
constructor(
multiaddr: Multiaddr,
hostPeerId: PeerId,
selfPeerId: PeerId,
handleParticle: (call: Particle) => void,
) {
this.selfPeerId = selfPeerId;
this.handleParticle = handleParticle;
this.selfPeerIdStr = selfPeerId.toB58String();
this.address = multiaddr;
this.nodePeerId = hostPeerId;
}
static async createConnection(options: FluenceConnectionOptions): Promise<FluenceConnection> {
const res = new FluenceConnection();
async connect(options?: FluenceConnectionOptions) {
await this.createPeer(options);
await this.startReceiving();
}
isConnected() {
return this.status === Status.Connected;
}
// connection status. If `Disconnected`, it cannot be reconnected
private status: Status = Status.Initializing;
private async createPeer(options?: FluenceConnectionOptions) {
const peerInfo = this.selfPeerId;
const transportKey = Websockets.prototype[Symbol.toStringTag];
this.node = await Peer.create({
peerId: peerInfo,
res._lib2p2Peer = await Lib2p2Peer.create({
peerId: options.peerId,
modules: {
transport: [Websockets],
streamMuxer: [Mplex],
@ -105,78 +76,74 @@ export class FluenceConnection {
},
},
dialer: {
dialTimeout: options?.dialTimeout,
dialTimeout: options?.dialTimeoutMs,
},
});
}
private async startReceiving() {
if (this.status === Status.Initializing) {
await this.node.start();
log.debug(`dialing to the node with client's address: ` + this.node.peerId.toB58String());
try {
await this.node.dial(this.address);
} catch (e1) {
const e = e1 as any;
if (e.name === 'AggregateError' && e._errors.length === 1) {
const error = e._errors[0];
throw `Error dialing node ${this.address}:\n${error.code}\n${error.message}`;
} else {
throw e;
}
}
this.node.handle([PROTOCOL_NAME], async ({ connection, stream }) => {
pipe(stream.source, decode(), async (source: AsyncIterable<string>) => {
for await (const msg of source) {
try {
const particle = parseParticle(msg);
logParticle(log.debug, 'Particle is received:', particle);
this.handleParticle(particle);
} catch (e) {
log.error('error on handling a new incoming message: ' + e);
}
res._lib2p2Peer.handle([PROTOCOL_NAME], async ({ connection, stream }) => {
pipe(stream.source, decode(), async (source: AsyncIterable<string>) => {
for await (const msg of source) {
try {
const particle = Particle.fromString(msg);
options.onIncomingParticle(particle);
} catch (e) {
log.error('error on handling a new incoming message: ' + e);
}
});
}
});
});
this.status = Status.Connected;
} else {
throw Error(`can't start receiving. Status: ${this.status}`);
}
}
res._relayAddress = options.relayAddress;
private checkConnectedOrThrow() {
if (this.status !== Status.Connected) {
throw Error(`connection is in ${this.status} state`);
}
return res;
}
async disconnect() {
await this.node.stop();
this.status = Status.Disconnected;
await this._lib2p2Peer.stop();
}
async sendParticle(particle: Particle): Promise<void> {
this.checkConnectedOrThrow();
public async sendParticle(particle: Particle): Promise<void> {
particle.logTo('debug', 'sending particle:');
let action = toPayload(particle);
let particleStr = JSON.stringify(action);
logParticle(log.debug, 'send particle: \n', particle);
/*
TODO:: find out why this doesn't work and a new connection has to be established each time
if (this._connection.streams.length !== 1) {
throw 'Incorrect number of streams in FluenceConnection';
}
// create outgoing substream
const conn = (await this.node.dialProtocol(this.address, PROTOCOL_NAME)) as {
stream;
protocol: string;
};
const sink = this._connection.streams[0].sink;
*/
const conn = await this._lib2p2Peer.dialProtocol(this._relayAddress, PROTOCOL_NAME);
const sink = conn.stream.sink;
pipe(
[Buffer.from(particleStr, 'utf8')],
// at first, make a message varint
// force new line
[Buffer.from(particle.toString(), 'utf8')],
encode(),
conn.stream.sink,
sink,
);
}
public async connect() {
await this._lib2p2Peer.start();
log.debug(`dialing to the node with client's address: ` + this._lib2p2Peer.peerId.toB58String());
try {
this._connection = await this._lib2p2Peer.dial(this._relayAddress);
} catch (e1) {
const e = e1 as any;
if (e.name === 'AggregateError' && e._errors.length === 1) {
const error = e._errors[0];
throw `Error dialing node ${this._relayAddress}:\n${error.code}\n${error.message}`;
} else {
throw e;
}
}
}
private _lib2p2Peer: Lib2p2Peer;
private _connection: Connection;
private _relayAddress: Multiaddr;
}

View File

@ -1,19 +1,42 @@
import { AirInterpreter, CallServiceResult, LogLevel, ParticleHandler, SecurityTetraplet } from '@fluencelabs/avm';
import log from 'loglevel';
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
AirInterpreter,
CallRequestsArray,
CallResultsArray,
InterpreterResult,
LogLevel,
CallServiceResult as AvmCallServiceResult,
} from '@fluencelabs/avm';
import { Multiaddr } from 'multiaddr';
import PeerId from 'peer-id';
import { CallServiceHandler } from './CallServiceHandler';
import { CallServiceData, CallServiceResult, GenericCallServiceHandler, ResultCodes } from './commonTypes';
import { CallServiceHandler as LegacyCallServiceHandler } from './compilerSupport/LegacyCallServiceHandler';
import { PeerIdB58 } from './commonTypes';
import makeDefaultClientHandler from './defaultClientHandler';
import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection';
import { logParticle, Particle } from './particle';
import { FluenceConnection } from './FluenceConnection';
import { Particle } from './Particle';
import { KeyPair } from './KeyPair';
import { RequestFlow } from './RequestFlow';
import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder';
import { createInterpreter } from './utils';
import { createInterpreter, dataToString } from './utils';
import { filter, pipe, Subject, tap } from 'rxjs';
import { RequestFlow } from './compilerSupport/v1';
import log from 'loglevel';
import { defaultServices } from './defaultServices';
/**
* Node of the Fluence detwork specified as a pair of node's multiaddr and it's peer id
* Node of the Fluence network specified as a pair of node's multiaddr and it's peer id
*/
type Node = {
peerId: PeerIdB58;
@ -26,6 +49,8 @@ type Node = {
*/
export type AvmLoglevel = LogLevel;
const DEFAULT_TTL = 7000;
/**
* Configuration used when initiating Fluence Peer
*/
@ -123,15 +148,11 @@ export class FluencePeer {
* Get the peer's status
*/
getStatus(): PeerStatus {
let isConnected = false;
if (this._connection) {
isConnected = this._connection?.isConnected();
}
const hasKeyPair = this._keyPair !== undefined;
return {
isInitialized: hasKeyPair,
isConnected: isConnected,
peerId: this._selfPeerId,
isConnected: this._connection !== undefined,
peerId: this._keyPair?.Libp2pPeerId?.toB58String() || null,
relayPeerId: this._relayPeerId || null,
};
}
@ -148,30 +169,52 @@ export class FluencePeer {
this._keyPair = await KeyPair.randomEd25519();
}
await this._initAirInterpreter(config?.avmLogLevel || 'off');
this._callServiceHandler = makeDefaultClientHandler();
this._interpreter = await createInterpreter(config?.avmLogLevel || 'off');
if (config?.connectTo) {
let theAddress: Multiaddr;
let connectToMultiAddr: Multiaddr;
let fromNode = (config.connectTo as any).multiaddr;
if (fromNode) {
theAddress = new Multiaddr(fromNode);
connectToMultiAddr = new Multiaddr(fromNode);
} else {
theAddress = new Multiaddr(config.connectTo as string);
connectToMultiAddr = new Multiaddr(config.connectTo as string);
}
await this._connect(theAddress);
this._relayPeerId = connectToMultiAddr.getPeerId();
if (this._connection) {
await this._connection.disconnect();
}
this._connection = await FluenceConnection.createConnection({
peerId: this._keyPair.Libp2pPeerId,
relayAddress: connectToMultiAddr,
dialTimeoutMs: config.dialTimeoutMs,
onIncomingParticle: (p) => this._incomingParticles.next(p),
});
await this._connect();
}
this._legacyCallServiceHandler = new LegacyCallServiceHandler();
registerDefaultServices(this);
this._startParticleProcessing();
}
/**
* Uninitializes the peer: stops all the underltying workflows, stops the Aqua VM
* Un-initializes the peer: stops all the underlying workflows, stops the Aqua VM
* and disconnects from the Fluence network
*/
async stop() {
this._stopParticleProcessing();
await this._disconnect();
this._callServiceHandler = null;
this._relayPeerId = null;
this._legacyCallServiceHandler = null;
this._particleSpecificHandlers.clear();
this._commonHandlers.clear();
this._timeoutHandlers.clear();
}
// internal api
@ -181,8 +224,80 @@ export class FluencePeer {
*/
get internals() {
return {
initiateFlow: this._initiateFlow.bind(this),
callServiceHandler: this._callServiceHandler,
/**
* Initiates a new particle execution starting from local peer
* @param particle - particle to start execution of
*/
initiateParticle: (particle: Particle): void => {
if (particle.initPeerId === undefined) {
particle.initPeerId = this.getStatus().peerId;
}
if (particle.ttl === undefined) {
particle.ttl = DEFAULT_TTL;
}
this._incomingParticles.next(particle);
},
/**
* Register Call Service handler functions
*/
regHandler: {
/**
* Register handler for all particles
*/
common: (
// force new line
serviceId: string,
fnName: string,
handler: GenericCallServiceHandler,
) => {
this._commonHandlers.set(serviceFnKey(serviceId, fnName), handler);
},
/**
* Register handler which will be called only for particle with the specific id
*/
forParticle: (
particleId: string,
serviceId: string,
fnName: string,
handler: GenericCallServiceHandler,
) => {
let psh = this._particleSpecificHandlers.get(particleId);
if (psh === undefined) {
psh = new Map<string, GenericCallServiceHandler>();
this._particleSpecificHandlers.set(particleId, psh);
}
psh.set(serviceFnKey(serviceId, fnName), handler);
},
/**
* Register handler which will be called upon particle timeout
*/
timeout: (particleId: string, handler: () => void) => {
this._timeoutHandlers.set(particleId, handler);
},
},
/**
* @deprecated
*/
initiateFlow: (request: RequestFlow): void => {
const particle = request.particle;
this._legacyParticleSpecificHandlers.set(particle.id, {
handler: request.handler,
error: request.error,
timeout: request.timeout,
});
this.internals.initiateParticle(particle);
},
/**
* @deprecated
*/
callServiceHandler: this._legacyCallServiceHandler,
};
}
@ -193,153 +308,274 @@ export class FluencePeer {
*/
private _isFluenceAwesome = true;
private async _initiateFlow(request: RequestFlow): Promise<void> {
// setting `relayVariableName` here. If the client is not connected (i.e it is created as local) then there is no relay
request.handler.on(loadVariablesService, loadRelayFn, () => {
return this._relayPeerId || '';
});
await request.initState(this._keyPair.Libp2pPeerId);
logParticle(log.debug, 'executing local particle', request.getParticle());
request.handler.combineWith(this._callServiceHandler);
this._requests.set(request.id, request);
this._processRequest(request);
}
private _callServiceHandler: CallServiceHandler;
private _keyPair: KeyPair;
private _requests: Map<string, RequestFlow> = new Map();
private _currentRequestId: string | null = null;
private _watchdog;
private _connection: FluenceConnection;
private _interpreter: AirInterpreter;
private async _initAirInterpreter(logLevel: AvmLoglevel): Promise<void> {
this._interpreter = await createInterpreter(this._interpreterCallback.bind(this), this._selfPeerId, logLevel);
}
private async _connect(multiaddr: Multiaddr, options?: FluenceConnectionOptions): Promise<void> {
const nodePeerId = multiaddr.getPeerId();
if (!nodePeerId) {
throw Error("'multiaddr' did not contain a valid peer id");
}
if (this._connection) {
await this._connection.disconnect();
}
const node = PeerId.createFromB58String(nodePeerId);
const connection = new FluenceConnection(
multiaddr,
node,
this._keyPair.Libp2pPeerId,
this._executeIncomingParticle.bind(this),
);
await connection.connect(options);
this._connection = connection;
this._initWatchDog();
// TODO:: make public when full connection\disconnection cycle is implemented properly
private async _connect(): Promise<void> {
return this._connection?.connect();
}
// TODO:: make public when full connection\disconnection cycle is implemented properly
private async _disconnect(): Promise<void> {
if (this._connection) {
await this._connection.disconnect();
return this._connection.disconnect();
}
this._clearWathcDog();
this._requests.forEach((r) => {
r.cancel();
}
// Queues for incoming and outgoing particles
private _incomingParticles = new Subject<Particle>();
private _outgoingParticles = new Subject<Particle>();
// Call service handler
private _particleSpecificHandlers = new Map<string, Map<string, GenericCallServiceHandler>>();
private _commonHandlers = new Map<string, GenericCallServiceHandler>();
private _timeoutHandlers = new Map<string, () => void>();
// Internal peer state
private _relayPeerId: PeerIdB58 | null = null;
private _keyPair: KeyPair;
private _connection: FluenceConnection;
private _interpreter: AirInterpreter;
private _timeouts: Array<NodeJS.Timeout> = [];
private _startParticleProcessing() {
const particleQueues = new Map<string, Subject<Particle>>();
this._incomingParticles
.pipe(
tap((x) => x.logTo('debug', 'particle received:')),
filterExpiredParticles(),
)
.subscribe((p) => {
let particlesQueue = particleQueues.get(p.id);
if (!particlesQueue) {
particlesQueue = this._createParticlesProcessingQueue();
particleQueues.set(p.id, particlesQueue);
const timeout = setTimeout(() => {
log.debug(`particle ${p.id} has expired. Deleting particle-related queues and handlers`);
particleQueues.delete(p.id);
const timeoutHandler = this._timeoutHandlers.get(p.id);
if (timeoutHandler) {
timeoutHandler();
}
this._particleSpecificHandlers.delete(p.id);
this._timeoutHandlers.delete(p.id);
}, p.actualTtl());
this._timeouts.push(timeout);
}
particlesQueue.next(p);
});
this._outgoingParticles.subscribe((p) => {
this._connection.sendParticle(p);
});
}
private get _selfPeerId(): PeerIdB58 | null {
return this._keyPair?.Libp2pPeerId?.toB58String() || null;
private _createParticlesProcessingQueue() {
let particlesQueue = new Subject<Particle>();
let prevData: Uint8Array = Buffer.from([]);
particlesQueue
.pipe(
// force new line
filterExpiredParticles(),
)
.subscribe((x) => {
const result = runInterpreter(this.getStatus().peerId, this._interpreter, x, prevData);
prevData = Buffer.from(result.data);
// send particle further if requested
if (result.nextPeerPks.length > 0) {
const newParticle = x.clone();
newParticle.data = prevData;
this._outgoingParticles.next(newParticle);
}
// execute call requests if needed
// and put particle with the results back to queue
if (result.callRequests.length > 0) {
this._execCallRequests(x, result.callRequests).then((callResults) => {
const newParticle = x.clone();
newParticle.callResults = callResults;
newParticle.data = Buffer.from([]);
particlesQueue.next(newParticle);
});
}
});
return particlesQueue;
}
private get _relayPeerId(): PeerIdB58 | null {
return this._connection?.nodePeerId?.toB58String() || null;
}
private async _execCallRequests(p: Particle, callRequests: CallRequestsArray): Promise<CallResultsArray> {
// execute all requests asynchronously
const promises = callRequests.map(([key, callRequest]) => {
const req = {
fnName: callRequest.functionName,
args: callRequest.arguments,
serviceId: callRequest.serviceId,
tetraplets: callRequest.tetraplets,
particleContext: p.getParticleContext(),
};
private async _executeIncomingParticle(particle: Particle) {
logParticle(log.debug, 'incoming particle received', particle);
// execute single requests and catch possible errors
const promise = this._execSingleCallRequest(req)
.catch(
(err): CallServiceResult => ({
retCode: ResultCodes.exceptionInHandler,
result: `Handler failed. fnName="${req.fnName}" serviceId="${
req.serviceId
}" error: ${err.toString()}`,
}),
)
.then(
(res): AvmCallServiceResult => ({
result: JSON.stringify(res.result),
retCode: res.retCode,
}),
)
.then((res): [key: number, res: AvmCallServiceResult] => [key, res]);
let request = this._requests.get(particle.id);
if (request) {
await request.receiveUpdate(particle);
} else {
request = RequestFlow.createExternal(particle);
request.handler.combineWith(this._callServiceHandler);
}
this._requests.set(request.id, request);
await this._processRequest(request);
}
private _processRequest(request: RequestFlow) {
try {
this._currentRequestId = request.id;
request.execute(this._interpreter, this._connection, this._relayPeerId);
} catch (err) {
log.error('particle processing failed: ' + err);
} finally {
this._currentRequestId = null;
}
}
private _interpreterCallback: ParticleHandler = (
serviceId: string,
fnName: string,
args: any[],
tetraplets: SecurityTetraplet[][],
): CallServiceResult => {
if (this._currentRequestId === null) {
throw Error('current request can`t be null here');
}
const request = this._requests.get(this._currentRequestId);
const particle = request.getParticle();
if (particle === null) {
throw new Error("particle can't be null here, current request id: " + this._currentRequestId);
}
const res = request.handler.execute({
serviceId,
fnName,
args,
tetraplets,
particleContext: {
particleId: request.id,
initPeerId: particle.init_peer_id,
timestamp: particle.timestamp,
ttl: particle.ttl,
signature: particle.signature,
},
return promise;
});
// don't block
const res = await Promise.all(promises);
log.debug(`Executed call service for particle id=${p.id}, Call service results: `, res);
return res;
}
private async _execSingleCallRequest(req: CallServiceData): Promise<CallServiceResult> {
const particleId = req.particleContext.particleId;
// trying particle-specific handler
const lh = this._legacyParticleSpecificHandlers.get(particleId);
let res: CallServiceResult = {
result: undefined,
retCode: undefined,
};
if (lh !== undefined) {
res = lh.handler.execute(req);
}
// if it didn't return any result trying to run the common handler
if (res?.result === undefined) {
res = this._legacyCallServiceHandler.execute(req);
}
// No result from legacy handler.
// Trying to execute async handler
if (res.retCode === undefined) {
const key = serviceFnKey(req.serviceId, req.fnName);
const psh = this._particleSpecificHandlers.get(particleId);
let handler: GenericCallServiceHandler;
// we should prioritize handler for this particle if there is one
// if particle-specific handlers exist for this particle try getting handler there
if (psh !== undefined) {
handler = psh.get(key);
}
// then try to find a common handler for all particles with this service-fn key
// if there is no particle-specific handler, get one from common map
if (handler === undefined) {
handler = this._commonHandlers.get(key);
}
// if we found a handler, execute it
// otherwise return useful error message to AVM
res = handler
? await handler(req)
: {
retCode: ResultCodes.unknownError,
result: `No handler has been registered for serviceId='${req.serviceId}' fnName='${req.fnName}' args='${req.args}'`,
};
}
if (res.result === undefined) {
log.error(
`Call to serviceId=${serviceId} fnName=${fnName} unexpectedly returned undefined result, falling back to null. Particle id=${request.id}`,
);
res.result = null;
}
return {
ret_code: res.retCode,
result: JSON.stringify(res.result),
};
};
private _initWatchDog() {
this._watchdog = setInterval(() => {
for (let key in this._requests.keys) {
if (this._requests.get(key).hasExpired()) {
this._requests.delete(key);
}
}
}, 5000); // TODO: make configurable
return res;
}
private _clearWathcDog() {
clearInterval(this._watchdog);
private _stopParticleProcessing() {
// do not hang if the peer has been stopped while some of the timeouts are still being executed
for (let item of this._timeouts) {
clearTimeout(item);
}
}
/**
* @deprecated
*/
private _legacyParticleSpecificHandlers = new Map<
string,
{
handler: LegacyCallServiceHandler;
timeout?: () => void;
error?: (reason?: any) => void;
}
>();
/**
* @deprecated
*/
private _legacyCallServiceHandler: LegacyCallServiceHandler;
}
function serviceFnKey(serviceId: string, fnName: string) {
return `${serviceId}/${fnName}`;
}
function registerDefaultServices(peer: FluencePeer) {
for (let serviceId in defaultServices) {
for (let fnName in defaultServices[serviceId]) {
const h = defaultServices[serviceId][fnName];
peer.internals.regHandler.common(serviceId, fnName, h);
}
}
}
function runInterpreter(
currentPeerId: PeerIdB58,
interpreter: AirInterpreter,
particle: Particle,
prevData: Uint8Array,
): InterpreterResult {
particle.logTo('debug', 'Sending particle to interpreter');
log.debug('prevData: ', dataToString(prevData));
log.debug('data: ', dataToString(particle.data));
const interpreterResult = interpreter.invoke(
particle.script,
prevData,
particle.data,
{
initPeerId: particle.initPeerId,
currentPeerId: currentPeerId,
},
particle.callResults,
);
const toLog: any = { ...interpreterResult };
toLog.data = dataToString(toLog.data);
log.debug('Interpreter result: ', toLog);
return interpreterResult;
}
function filterExpiredParticles() {
return pipe(
tap((p: Particle) => {
if (p.hasExpired) {
log.debug(`particle ${p.id} has expired`);
}
}),
filter((x: Particle) => !x.hasExpired()),
);
}

View File

@ -15,7 +15,6 @@
*/
import * as PeerId from 'peer-id';
import * as base64 from 'base64-js';
import { keys } from 'libp2p-crypto';
export class KeyPair {

147
src/internal/Particle.ts Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { v4 as uuidv4 } from 'uuid';
import { fromByteArray, toByteArray } from 'base64-js';
import { CallResultsArray, LogLevel } from '@fluencelabs/avm';
import log from 'loglevel';
import { ParticleContext } from './commonTypes';
import { dataToString } from './utils';
const DefaultTTL = 7000;
export class Particle {
id: string;
initPeerId: string;
timestamp: number;
ttl: number;
script: string;
signature: string;
data: Uint8Array;
callResults: CallResultsArray = [];
static createNew(script: string, ttlMs?: number): Particle {
const res = new Particle();
res.id = genUUID();
res.script = script;
res.ttl = ttlMs || DefaultTTL;
res.data = Buffer.from([]);
res.timestamp = Date.now();
return res;
}
static fromString(str: string): Particle {
const json = JSON.parse(str);
const res = new Particle();
res.id = json.id;
res.initPeerId = json.init_peer_id;
res.timestamp = json.timestamp;
res.ttl = json.ttl;
res.script = json.script;
res.signature = json.signature;
res.data = toByteArray(json.data);
return res;
}
getParticleContext(): ParticleContext {
return {
particleId: this.id,
initPeerId: this.initPeerId,
timestamp: this.timestamp,
ttl: this.ttl,
signature: this.signature,
};
}
actualTtl(): number {
return this.timestamp + this.ttl - Date.now();
}
hasExpired(): boolean {
return this.actualTtl() <= 0;
}
clone(): Particle {
const res = new Particle();
res.id = this.id;
res.initPeerId = this.initPeerId;
res.timestamp = this.timestamp;
res.ttl = this.ttl;
res.script = this.script;
res.signature = this.signature;
res.data = this.data;
res.callResults = this.callResults;
return res;
}
toString(): string {
const particle = this;
const payload = {
action: 'Particle',
id: particle.id,
init_peer_id: particle.initPeerId,
timestamp: particle.timestamp,
ttl: particle.ttl,
script: particle.script,
// TODO: copy signature from a particle after signatures will be implemented on nodes
signature: [],
data: fromByteArray(particle.data),
};
return JSON.stringify(payload);
}
logTo(level: LogLevel, message: string) {
let fn;
let data;
switch (level) {
case 'debug':
fn = log.debug;
data = dataToString(this.data);
break;
case 'error':
fn = log.error;
break;
case 'info':
fn = log.info;
break;
case 'trace':
fn = log.trace;
break;
case 'warn':
fn = log.warn;
break;
default:
return;
}
fn(message, {
id: this.id,
init_peer_id: this.initPeerId,
timestamp: this.timestamp,
ttl: this.ttl,
script: this.script,
signature: this.signature,
data: data,
});
}
}
function genUUID() {
return uuidv4();
}

View File

@ -1,201 +0,0 @@
import log, { trace } from 'loglevel';
import PeerId from 'peer-id';
import { AirInterpreter } from '@fluencelabs/avm';
import { CallServiceHandler } from './CallServiceHandler';
import { PeerIdB58 } from './commonTypes';
import { FluenceConnection } from './FluenceConnection';
import { Particle, genUUID, logParticle } from './particle';
import { ParticleDataToString } from './utils';
export const DEFAULT_TTL = 7000;
interface InterpreterOutcome {
ret_code: number;
data: Uint8Array;
next_peer_pks: string[];
error_message: string;
}
/**
* The class represents the current view (and state) of distributed the particle execution process from client's point of view.
* It stores the intermediate particles state during the process. RequestFlow is identified by the id of the particle that is executed during the flow.
* Each RequestFlow contains a separate (unique to the current flow) CallServiceHandler where the handling of `call` AIR instruction takes place
* Please note, that RequestFlow's is handler is combined with the handler from client before the execution occures.
* After the combination middlewares from RequestFlow are executed before client handler's middlewares.
*/
export class RequestFlow {
private state: Particle;
private prevData: Uint8Array = Buffer.from([]);
private onTimeoutHandlers = [];
private onErrorHandlers = [];
private timeoutHandle?: NodeJS.Timeout;
readonly id: string;
readonly isExternal: boolean;
readonly script: string;
readonly handler = new CallServiceHandler();
ttl: number = DEFAULT_TTL;
relayPeerId?: PeerIdB58;
static createExternal(particle: Particle): RequestFlow {
const res = new RequestFlow(true, particle.id, particle.script);
res.ttl = particle.ttl;
res.state = particle;
res.timeoutHandle = setTimeout(res.raiseTimeout.bind(res), particle.ttl);
return res;
}
static createLocal(script: string, ttl?: number): RequestFlow {
const res = new RequestFlow(false, genUUID(), script);
res.ttl = ttl ?? DEFAULT_TTL;
return res;
}
constructor(isExternal: boolean, id: string, script: string) {
this.isExternal = isExternal;
this.id = id;
this.script = script;
}
onTimeout(handler: () => void) {
this.onTimeoutHandlers.push(handler);
}
onError(handler: (error) => void) {
this.onErrorHandlers.push(handler);
}
async execute(interpreter: AirInterpreter, connection: FluenceConnection, relayPeerId?: PeerIdB58) {
if (this.hasExpired()) {
return;
}
logParticle(log.debug, 'interpreter executing particle', this.getParticle());
const interpreterOutcome = this.runInterpreter(interpreter);
log.debug('inner interpreter outcome:', {
particleId: this.getParticle()?.id,
ret_code: interpreterOutcome.ret_code,
error_message: interpreterOutcome.error_message,
next_peer_pks: interpreterOutcome.next_peer_pks,
});
if (interpreterOutcome.ret_code !== 0) {
this.raiseError(
`Interpreter failed with code=${interpreterOutcome.ret_code} message=${interpreterOutcome.error_message}`,
);
}
const nextPeers = interpreterOutcome.next_peer_pks;
// do nothing if there are no peers to send particle further
if (nextPeers.length === 0) {
return;
}
// we only expect a single possible peer id to send particle further
if (nextPeers.length > 1) {
this.throwIncorrectNextPeerPks(nextPeers);
}
// this peer id must be the relay, the client is connected to
if (!relayPeerId || nextPeers[0] !== relayPeerId) {
this.throwIncorrectNextPeerPks(nextPeers);
}
if (!connection) {
this.raiseError('Cannot send particle: non connected');
return;
}
this.sendIntoConnection(connection);
}
public cancel() {
if (this.timeoutHandle) {
clearTimeout(this.timeoutHandle);
}
}
private throwIncorrectNextPeerPks(nextPeers: PeerIdB58[]) {
this.raiseError(
`Particle is expected to be sent to only the single peer (relay which client is connected to).
particle id: ${this.getParticle()?.id}
next peers: ${nextPeers.join(' ')}
relay peer id: ${this.relayPeerId}
`,
);
}
async initState(peerId: PeerId): Promise<void> {
const id = this.id;
let currentTime = Date.now();
const particle: Particle = {
id: id,
init_peer_id: peerId.toB58String(),
timestamp: currentTime,
ttl: this.ttl,
script: this.script,
signature: '',
data: Buffer.from([]),
};
this.state = particle;
this.timeoutHandle = setTimeout(this.raiseTimeout.bind(this), particle.ttl);
}
receiveUpdate(particle: Particle) {
// TODO:: keep the history of particle data mb?
this.prevData = this.state.data;
this.state.data = particle.data;
}
async sendIntoConnection(connection: FluenceConnection): Promise<void> {
const particle = this.state;
try {
await connection.sendParticle(particle);
} catch (err) {
log.error(`Error on sending particle with id ${particle.id}: ${err}`);
}
}
runInterpreter(interpreter: AirInterpreter) {
const interpreterOutcomeStr = interpreter.invoke(
this.state.init_peer_id,
this.state.script,
this.prevData,
this.state.data,
);
const interpreterOutcome: InterpreterOutcome = JSON.parse(interpreterOutcomeStr);
// TODO:: keep the history of particle data mb?
this.state.data = interpreterOutcome.data;
return interpreterOutcome;
}
getParticle = () => this.state;
hasExpired(): boolean {
let now = Date.now();
const particle = this.getParticle();
let actualTtl = particle.timestamp + particle.ttl - now;
return actualTtl <= 0;
}
raiseError(error) {
for (const h of this.onErrorHandlers) {
h(error);
}
}
private raiseTimeout() {
const now = Date.now();
const particle = this.state;
log.info(`Particle expired. Now: ${now}, ttl: ${particle?.ttl}, ts: ${particle?.timestamp}`);
for (const h of this.onTimeoutHandlers) {
h();
}
}
}

View File

@ -1,333 +0,0 @@
import log from 'loglevel';
import { CallServiceHandler, CallServiceResultType } from './CallServiceHandler';
import { DEFAULT_TTL, RequestFlow } from './RequestFlow';
export const loadVariablesService = 'load';
const loadVariablesFn = 'load_variable';
export const loadRelayFn = 'load_relay';
const xorHandleService = '__magic';
const xorHandleFn = 'handle_xor';
export const relayVariableName = 'init_relay';
const wrapWithXor = (script: string): string => {
return `
(xor
${script}
(xor
(match ${relayVariableName} ""
(call %init_peer_id% ("${xorHandleService}" "${xorHandleFn}") [%last_error%])
)
(seq
(call ${relayVariableName} ("op" "identity") [])
(call %init_peer_id% ("${xorHandleService}" "${xorHandleFn}") [%last_error%])
)
)
)`;
};
class ScriptBuilder {
private script: string;
private isXorInjected: boolean;
private shouldInjectRelay: boolean;
private variables: string[] = [];
constructor() {
this.isXorInjected = false;
this.shouldInjectRelay = false;
}
raw(script: string): ScriptBuilder {
this.script = script;
return this;
}
withInjectedVariables(fields: string[]): ScriptBuilder {
this.variables = [...this.variables, ...fields];
return this;
}
wrappedWithXor(): ScriptBuilder {
this.isXorInjected = true;
return this;
}
withInjectedRelay(): ScriptBuilder {
this.shouldInjectRelay = true;
return this;
}
build(): string {
let script = this.script;
if (this.withInjectedVariables && this.withInjectedVariables.length > 0) {
script = wrapWithVariableInjectionScript(script, this.variables);
}
if (this.isXorInjected) {
script = wrapWithXor(script);
}
if (this.shouldInjectRelay) {
script = wrapWithInjectRelayScript(script);
}
return script;
}
}
const wrapWithVariableInjectionScript = (script: string, fields: string[]): string => {
fields.forEach((v) => {
script = `
(seq
(call %init_peer_id% ("${loadVariablesService}" "${loadVariablesFn}") ["${v}"] ${v})
${script}
)`;
});
return script;
};
const wrapWithInjectRelayScript = (script: string): string => {
return `
(seq
(call %init_peer_id% ("${loadVariablesService}" "${loadRelayFn}") [] ${relayVariableName})
${script}
)`;
};
/**
* Builder class for configuring and creating Request Flows
*/
export class RequestFlowBuilder {
private shouldInjectVariables: boolean = true;
private shouldInjectErrorHandling: boolean = true;
private shouldInjectRelay: boolean = true;
private ttl: number = DEFAULT_TTL;
private variables = new Map<string, CallServiceResultType>();
private handlerConfigs: Array<(handler: CallServiceHandler, request: RequestFlow) => void> = [];
private buildScriptActions: Array<(sb: ScriptBuilder) => void> = [];
private onTimeout: () => void;
private onError: (error: any) => void;
/**
* Builds the Request flow with current configuration
*/
build() {
if (this.shouldInjectRelay) {
this.injectRelay();
}
if (this.shouldInjectVariables) {
this.injectVariables();
}
if (this.shouldInjectErrorHandling) {
this.wrapWithXor();
}
const sb = new ScriptBuilder();
for (let action of this.buildScriptActions) {
action(sb);
}
let script = sb.build();
const res = RequestFlow.createLocal(script, this.ttl);
for (let h of this.handlerConfigs) {
h(res.handler, res);
}
if (this.onTimeout) {
res.onTimeout(this.onTimeout);
}
if (this.onError) {
res.onError(this.onError);
}
return res;
}
/**
* Removes necessary defaults when building requests by hand without the Aqua language compiler
* Removed features include: relay and variable injection, error handling with top-level xor wrap
*/
disableInjections(): RequestFlowBuilder {
this.shouldInjectRelay = false;
this.shouldInjectVariables = false;
this.shouldInjectErrorHandling = false;
return this;
}
/**
* Injects `init_relay` variable into the script
*/
injectRelay(): RequestFlowBuilder {
this.configureScript((sb) => {
sb.withInjectedRelay();
});
return this;
}
/**
* Registers services for variable injection. Required for variables registration to work
*/
injectVariables(): RequestFlowBuilder {
this.configureScript((sb) => {
sb.withInjectedVariables(Array.from(this.variables.keys()));
});
this.configHandler((h) => {
h.on(loadVariablesService, loadVariablesFn, (args, _) => {
if (this.variables.has(args[0])) {
return this.variables.get(args[0]);
}
throw new Error(`failed to inject variable: ${args[0]}`);
});
});
return this;
}
/**
* Wraps the script with top-level error handling with xor instruction. Will raise error in the Request Flow in xor catches any error
*/
wrapWithXor(): RequestFlowBuilder {
this.configureScript((sb) => {
sb.wrappedWithXor();
});
this.configHandler((h, request) => {
h.onEvent(xorHandleService, xorHandleFn, (args) => {
if (args[0] === undefined) {
log.error(
'Request flow error handler recieved unexpected argument, value of %last_error% is undefined',
);
}
try {
request.raiseError(args[0]);
} catch (e) {
log.error('Error handling script executed with error', e);
}
});
});
return this;
}
/**
* Use ScriptBuilder provided by action in argument to configure script of the Request Flow
*/
configureScript(action: (sb: ScriptBuilder) => void): RequestFlowBuilder {
this.buildScriptActions.push(action);
return this;
}
/**
* Use raw text as script for the Request Flow
*/
withRawScript(script: string): RequestFlowBuilder {
this.buildScriptActions.push((sb) => {
sb.raw(script);
});
return this;
}
/**
* Specify time to live for the request
*/
withTTL(ttl?: number): RequestFlowBuilder {
if (ttl) {
this.ttl = ttl;
}
return this;
}
/**
* Configure local call handler for the Request Flow
*/
configHandler(config: (handler: CallServiceHandler, request: RequestFlow) => void): RequestFlowBuilder {
this.handlerConfigs.push(config);
return this;
}
/**
* Specifies handler for the particle timeout event
*/
handleTimeout(handler: () => void): RequestFlowBuilder {
this.onTimeout = handler;
return this;
}
/**
* Specifies handler for any script errors
*/
handleScriptError(handler: (error) => void): RequestFlowBuilder {
this.onError = handler;
return this;
}
/**
* Adds a variable to the list of injected variables
*/
withVariable(name: string, value: CallServiceResultType): RequestFlowBuilder {
this.variables.set(name, value);
return this;
}
/**
* Adds a multiple variable to the list of injected variables.
* Variables can be specified in form of either object or a map where keys correspond to variable names
*/
withVariables(
data: Map<string, CallServiceResultType> | Record<string, CallServiceResultType>,
): RequestFlowBuilder {
if (data instanceof Map) {
this.variables = new Map([...Array.from(this.variables.entries()), ...Array.from(data.entries())]);
} else {
for (let k in data) {
this.variables.set(k, data[k]);
}
}
return this;
}
/**
* Builds the Request flow with current configuration with a fetch-single-result semantics
* returns a tuple of [RequestFlow, promise] where promise is a fetch-like promise resolved when
* the execution hits callback service and rejected when particle times out or any error happens
*/
buildAsFetch<T>(
callbackServiceId: string = 'callback',
callbackFnName: string = 'callback',
): [RequestFlow, Promise<T>] {
const fetchPromise = new Promise<T>((resolve, reject) => {
this.handlerConfigs.push((h) => {
h.onEvent(callbackServiceId, callbackFnName, (args, _) => {
resolve(args as any);
});
});
this.handleTimeout(() => {
reject(`Timed out after ${this.ttl}ms`);
});
this.handleScriptError((e) => {
reject(e);
});
});
return [this.build(), fetchPromise];
}
/**
* Builds the Request flow with current configuration with error handling
* returns a tuple of [RequestFlow, promise]. The promise is never resolved and rejected in case of any error in the script
*/
buildWithErrorHandling(): [RequestFlow, Promise<void>] {
const promise = new Promise<void>((resolve, reject) => {
this.handleScriptError(reject);
});
return [this.build(), promise];
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { SecurityTetraplet } from '@fluencelabs/avm';
import { CallRequest, SecurityTetraplet } from '@fluencelabs/avm';
/**
* Peer ID's id as a base58 string (multihash/CIDv0).
@ -39,7 +39,7 @@ export interface CallParams<ArgName extends string | null> {
/**
* Particle's timestamp when it was created
*/
timeStamp: number;
timestamp: number;
/**
* Time to live in milliseconds. The time after the particle should be expired
@ -56,3 +56,78 @@ export interface CallParams<ArgName extends string | null> {
*/
tetraplets: { [key in ArgName]: SecurityTetraplet[] };
}
export enum ResultCodes {
success = 0,
unknownError = 1,
exceptionInHandler = 2,
}
/**
* Particle context. Contains additional information about particle which triggered `call` air instruction from AVM
*/
export interface ParticleContext {
/**
* The particle ID
*/
particleId: string;
initPeerId: PeerIdB58;
timestamp: number;
ttl: number;
signature: string;
}
/**
* Represents the information passed from AVM when a `call` air instruction is executed on the local peer
*/
export interface CallServiceData {
/**
* Service ID as specified in `call` air instruction
*/
serviceId: string;
/**
* Function name as specified in `call` air instruction
*/
fnName: string;
/**
* Arguments as specified in `call` air instruction
*/
args: any[];
/**
* Security Tetraplets received from AVM
*/
tetraplets: SecurityTetraplet[][];
/**
* Particle context, @see {@link ParticleContext}
*/
particleContext: ParticleContext;
}
/**
* Type for all the possible objects that can be return to the AVM
*/
export type CallServiceResultType = object | boolean | number | string | null;
/**
* Generic call service handler
*/
export type GenericCallServiceHandler = (req: CallServiceData) => CallServiceResult | Promise<CallServiceResult>;
/**
* Represents the result of the `call` air instruction to be returned into AVM
*/
export interface CallServiceResult {
/**
* Return code to be returned to AVM
*/
retCode: ResultCodes;
/**
* Result object to be returned to AVM
*/
result: CallServiceResultType;
}

View File

@ -1,82 +1,58 @@
import { SecurityTetraplet } from '@fluencelabs/avm';
import { PeerIdB58 } from './commonTypes';
export enum ResultCodes {
success = 0,
unkownError = 1,
exceptionInHandler = 2,
}
/**
* Particle context. Contains additional information about particle which triggered `call` air instruction from AVM
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
interface ParticleContext {
/**
* The particle ID
*/
particleId: string;
initPeerId: PeerIdB58;
timestamp: number;
ttl: number;
signature: string;
}
import { CallServiceData, CallServiceResult, CallServiceResultType, ResultCodes } from '../commonTypes';
/**
* Represents the information passed from AVM when a `call` air instruction is executed on the local peer
* @deprecated This class exists to glue legacy RequestFlowBuilder api with restructured async FluencePeer.
* v2 version of compiler support should be used instead
*/
export interface CallServiceData {
/**
* Service ID as specified in `call` air instruction
*/
serviceId: string;
export const callLegacyCallServiceHandler = (
req: CallServiceData,
commonHandler: CallServiceHandler,
particleSpecificHandler?: CallServiceHandler,
): CallServiceResult => {
// trying particle-specific handler
if (particleSpecificHandler !== undefined) {
var res = particleSpecificHandler.execute(req);
}
/**
* Function name as specified in `call` air instruction
*/
fnName: string;
if (res?.result === undefined) {
// if it didn't return any result trying to run the common handler
res = commonHandler.execute(req);
}
/**
* Arguments as specified in `call` air instruction
*/
args: any[];
if (res.retCode === undefined) {
res = {
retCode: ResultCodes.unknownError,
result: `The handler did not set any result. Make sure you are calling the right peer and the handler has been registered. Original request data was: serviceId='${req.serviceId}' fnName='${req.fnName}' args='${req.args}'`,
};
}
/**
* Security Tetraplets recieved from AVM
*/
tetraplets: SecurityTetraplet[][];
if (res.result === undefined) {
res.result = null;
}
/**
* Particle context, @see {@link ParticleContext}
*/
particleContext: ParticleContext;
[x: string]: any;
}
/**
* Type for all the possible ovjects that can be return to the AVM
*/
export type CallServiceResultType = object | boolean | number | string | null;
/**
* Represents the result of the `call` air instruction to be returned into AVM
*/
export interface CallServiceResult {
/**
* Return code to be returned to AVM
*/
retCode: ResultCodes;
/**
* Result object to be returned to AVM
*/
result: CallServiceResultType;
[x: string]: any;
}
return res;
};
/**
* @deprecated
* Type for the middleware used in CallServiceHandler middleware chain.
* In a nutshell middelware is a function of request, response and function to trigger the next middleware in chain.
* In a nutshell middleware is a function of request, response and function to trigger the next middleware in chain.
* Each middleware is free to write additional properties to either request or response object.
* When the chain finishes the response is passed back to AVM
* @param { CallServiceData } req - information about the air `call` instruction
@ -85,22 +61,14 @@ export interface CallServiceResult {
*/
export type Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => void;
export class CallServiceArg<T> {
val: T;
tetraplet: SecurityTetraplet[];
constructor(val: T, tetraplet: SecurityTetraplet[]) {
this.val = val;
this.tetraplet = tetraplet;
}
}
type CallParams = ParticleContext & {
wrappedArgs: CallServiceArg<any>[];
};
/**
* @deprecated
*/
type CallParams = any;
/**
* Convenience middleware factory. Registeres a handler for a pair of 'serviceId/fnName'.
* @deprecated
* Convenience middleware factory. Registers a handler for a pair of 'serviceId/fnName'.
* The return value of the handler is passed back to AVM
* @param { string } serviceId - The identifier of service which would be used to make calls from AVM
* @param { string } fnName - The identifier of function which would be used to make calls from AVM
@ -113,7 +81,7 @@ export const fnHandler = (
) => {
return (req: CallServiceData, resp: CallServiceResult, next: Function): void => {
if (req.fnName === fnName && req.serviceId === serviceId) {
const res = handler(req.args, { ...req.particleContext, wrappedArgs: req.wrappedArgs });
const res = handler(req.args, req.particleContext);
resp.retCode = ResultCodes.success;
resp.result = res;
}
@ -122,7 +90,8 @@ export const fnHandler = (
};
/**
* Convenience middleware factory. Registeres a handler for a pair of 'serviceId/fnName'.
* @deprecated
* Convenience middleware factory. Registers a handler for a pair of 'serviceId/fnName'.
* Similar to @see { @link fnHandler } but instead returns and empty object immediately runs the handler asynchronously
* @param { string } serviceId - The identifier of service which would be used to make calls from AVM
* @param { string } fnName - The identifier of function which would be used to make calls from AVM
@ -136,7 +105,7 @@ export const fnAsEventHandler = (
return (req: CallServiceData, resp: CallServiceResult, next: Function): void => {
if (req.fnName === fnName && req.serviceId === serviceId) {
setTimeout(() => {
handler(req.args, { ...req.particleContext, wrappedArgs: req.wrappedArgs });
handler(req.args, req.particleContext);
}, 0);
resp.retCode = ResultCodes.success;
@ -146,10 +115,14 @@ export const fnAsEventHandler = (
};
};
/**
* @deprecated
*/
type CallServiceFunction = (req: CallServiceData, resp: CallServiceResult) => void;
/**
* Class defines the handling of a `call` air intruction executed by AVM on the local peer.
* @deprecated
* Class defines the handling of a `call` air instruction executed by AVM on the local peer.
* All the execution process is defined by the chain of middlewares - architecture popular among backend web frameworks.
* Each middleware has the form of `(req: Call, resp: CallServiceResult, next: Function) => void;`
* A handler starts with an empty middleware chain and does nothing.
@ -180,7 +153,7 @@ export class CallServiceHandler {
}
/**
* Combine handler with another one. Combintaion is done by copying middleware chain from the argument's handler into current one.
* Combine handler with another one. Combination is done by copying middleware chain from the argument's handler into current one.
* Please note, that current handler's middlewares take precedence over the ones from handler to be combined with
* @param { CallServiceHandler } other - CallServiceHandler to be combined with
*/
@ -190,7 +163,7 @@ export class CallServiceHandler {
}
/**
* Convinience method for registring @see { @link fnHandler } middleware
* Convenience method for registering @see { @link fnHandler } middleware
*/
on(
serviceId: string, // force format
@ -205,7 +178,7 @@ export class CallServiceHandler {
}
/**
* Convinience method for registring @see { @link fnAsEventHandler } middleware
* Convenience method for registering @see { @link fnAsEventHandler } middleware
*/
onEvent(
serviceId: string, // force format
@ -240,8 +213,8 @@ export class CallServiceHandler {
*/
execute(req: CallServiceData): CallServiceResult {
const res: CallServiceResult = {
retCode: ResultCodes.unkownError,
result: `The handler did not set any result. Make sure you are calling the right peer and the handler has been registered. Original request data was: serviceId='${req.serviceId}' fnName='${req.fnName}' args='${req.args}'`,
retCode: undefined,
result: undefined,
};
this.buildFunction()(req, res);
return res;

View File

@ -1,5 +1,87 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CallServiceHandler } from './LegacyCallServiceHandler';
import { Particle } from '../Particle';
export { FluencePeer } from '../FluencePeer';
export { ResultCodes } from '../../internal/CallServiceHandler';
export { RequestFlow } from '../../internal/RequestFlow';
export { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
export { CallParams } from '../commonTypes';
export { CallParams, ResultCodes } from '../commonTypes';
/**
* @deprecated This class exists to glue legacy RequestFlowBuilder api with restructured async FluencePeer.
* v2 version of compiler support should be used instead
*/
export interface RequestFlow {
particle: Particle;
handler: CallServiceHandler;
timeout?: () => void;
error?: (reason?: any) => void;
}
/**
* @deprecated This class exists to glue legacy RequestFlowBuilder api with restructured async FluencePeer.
* v2 version of compiler support should be used instead
*/
export class RequestFlowBuilder {
private _ttl?: number;
private _script?: string;
private _configs: any = [];
private _error: (reason?: any) => void = () => {};
private _timeout: () => void = () => {};
build(): RequestFlow {
let h = new CallServiceHandler();
for (let c of this._configs) {
c(h);
}
return {
particle: Particle.createNew(this._script!, this._ttl),
handler: h,
timeout: this._timeout,
error: this._error,
};
}
withTTL(ttl: number): RequestFlowBuilder {
this._ttl = ttl;
return this;
}
handleTimeout(timeout: () => void): RequestFlowBuilder {
this._timeout = timeout;
return this;
}
handleScriptError(reject: (reason?: any) => void): RequestFlowBuilder {
this._error = reject;
return this;
}
withRawScript(script: string): RequestFlowBuilder {
this._script = script;
return this;
}
disableInjections(): RequestFlowBuilder {
return this;
}
configHandler(h: (handler: CallServiceHandler) => void) {
this._configs.push(h);
return this;
}
}

View File

@ -0,0 +1,518 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SecurityTetraplet } from '@fluencelabs/avm';
import { match } from 'ts-pattern';
import { CallParams, Fluence, FluencePeer } from '../../index';
import { CallServiceData, GenericCallServiceHandler, CallServiceResult, ResultCodes } from '../commonTypes';
import { Particle } from '../Particle';
export { FluencePeer } from '../FluencePeer';
export { CallParams } from '../commonTypes';
/**
* Represents the Aqua Option type
*/
type OptionalType = {
/**
* Type descriptor. Used for pattern-matching
*/
tag: 'optional';
};
/**
* Represents the void type for functions and callbacks with no return value
*/
type VoidType = {
/**
* Type descriptor. Used for pattern-matching
*/
tag: 'void';
};
/**
* Represents all types other than Optional, Void, Callback and MultiReturn
*/
type PrimitiveType = {
/**
* Type descriptor. Used for pattern-matching
*/
tag: 'primitive';
};
/**
* Represents callbacks used in Aqua function arguments (`func` instruction)
*/
type CallbackType = {
/**
* Type descriptor. Used for pattern-matching
*/
tag: 'callback';
/**
* Callback definition
*/
callback: CallbackDef<OptionalType | PrimitiveType, VoidType | OptionalType | PrimitiveType>;
};
/**
* Represents the return type for functions which return multiple values
*/
type MultiReturnType = {
/**
* Type descriptor. Used for pattern-matching
*/
tag: 'multiReturn';
/**
* The description of types of the return values: Array of either primitive or optional types
*/
returnItems: Array<OptionalType | PrimitiveType>;
};
interface ArgDef<ArgType> {
/**
* The name of the argument in Aqua language
*/
name: string;
/**
* The type of the argument
*/
argType: ArgType;
}
interface CallbackDef<ArgType, ReturnType> {
/**
* Callback argument definitions: the list of ArgDefs
*/
argDefs: Array<ArgDef<ArgType>>;
/**
* Definition of the return type of callback
*/
returnType: ReturnType;
}
interface FunctionBodyDef
extends CallbackDef<
// force new line
OptionalType | PrimitiveType,
VoidType | OptionalType | PrimitiveType
> {
/**
* The name of the function in Aqua language
*/
functionName: string;
}
/**
* Definition of function (`func` instruction) generated by the Aqua compiler
*/
interface FunctionCallDef
extends CallbackDef<
OptionalType | PrimitiveType | CallbackType,
VoidType | OptionalType | PrimitiveType | MultiReturnType
> {
/**
* The name of the function in Aqua language
*/
functionName: string;
/**
* Names of the different entities used in generated air script
*/
names: {
/**
* The name of the relay variable
*/
relay: string;
/**
* The name of the serviceId used load variables at the beginning of the script
*/
getDataSrv: string;
/**
* The name of serviceId is used to execute callbacks for the current particle
*/
callbackSrv: string;
/**
* The name of the serviceId which is called to propagate return value to the generated function caller
*/
responseSrv: string;
/**
* The name of the functionName which is called to propagate return value to the generated function caller
*/
responseFnName: string;
/**
* The name of the serviceId which is called to report errors to the generated function caller
*/
errorHandlingSrv: string;
/**
* The name of the functionName which is called to report errors to the generated function caller
*/
errorFnName: string;
};
}
/**
* Definition of service registration function (`service` instruction) generated by the Aqua compiler
*/
interface ServiceDef {
/**
* Default service id. If the service has no default id the value should be undefined
*/
defaultServiceId?: string;
/**
* List of functions which the service consists of
*/
functions: Array<FunctionBodyDef>;
}
/**
* Convenience function to support Aqua `func` generation backend
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script
*
* @param rawFnArgs - raw arguments passed by user to the generated function
* @param def - function definition generated by the Aqua compiler
* @param script - air script with function execution logic generated by the Aqua compiler
*/
export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script: string) {
const { args, peer, config } = extractFunctionArgs(rawFnArgs, def.argDefs.length);
if (args.length !== def.argDefs.length) {
throw new Error('Incorrect number of arguments. Expecting ${def.argDefs.length}');
}
const promise = new Promise((resolve, reject) => {
const particle = Particle.createNew(script, config?.ttl);
for (let i = 0; i < def.argDefs.length; i++) {
const argDef = def.argDefs[i];
const arg = args[i];
const [serviceId, fnName, cb] = match(argDef.argType)
// for callback arguments we are registering particle-specific callback which executes the passed function
.with({ tag: 'callback' }, (callbackDef) => {
const fn = async (req: CallServiceData): Promise<CallServiceResult> => {
const args = convertArgsFromReqToUserCall(req, callbackDef.callback.argDefs);
// arg is function at this point
const result = await arg.apply(null, args);
let res;
switch (callbackDef.callback.returnType.tag) {
case 'void':
res = {};
break;
case 'primitive':
res = result;
break;
case 'optional':
res = tsToAquaOpt(result);
break;
}
return {
retCode: ResultCodes.success,
result: res,
};
};
return [def.names.callbackSrv, argDef.name, fn] as const;
})
// for optional types we are converting value to array representation in air
.with({ tag: 'optional' }, () => {
const fn = (req: CallServiceData): CallServiceResult => {
// arg is optional at this point
const res = tsToAquaOpt(arg);
return {
retCode: ResultCodes.success,
result: res,
};
};
return [def.names.getDataSrv, argDef.name, fn] as const;
})
// for primitive types wre are simply passing the value
.with({ tag: 'primitive' }, () => {
// arg is primitive at this point
const fn = (req: CallServiceData): CallServiceResult => ({
retCode: ResultCodes.success,
result: arg,
});
return [def.names.getDataSrv, argDef.name, fn] as const;
})
.exhaustive();
// registering handlers for every argument of the function
peer.internals.regHandler.forParticle(particle.id, serviceId, fnName, cb);
}
// registering handler for function response
peer.internals.regHandler.forParticle(particle.id, def.names.responseSrv, def.names.responseFnName, (req) => {
const userFunctionReturn = match(def.returnType)
.with({ tag: 'primitive' }, () => req.args[0])
.with({ tag: 'optional' }, () => aquaOptToTs(req.args[0]))
.with({ tag: 'void' }, () => undefined)
.with({ tag: 'multiReturn' }, (mr) => {
return mr.returnItems.map((x, index) => {
return match(x)
.with({ tag: 'optional' }, () => aquaOptToTs(req.args[index]))
.with({ tag: 'primitive' }, () => req.args[index])
.exhaustive();
});
})
.exhaustive();
setTimeout(() => {
resolve(userFunctionReturn);
}, 0);
return {
retCode: ResultCodes.success,
result: {},
};
});
// registering handler for injecting relay variable
peer.internals.regHandler.forParticle(particle.id, def.names.getDataSrv, def.names.relay, (req) => {
return {
retCode: ResultCodes.success,
result: peer.getStatus().relayPeerId,
};
});
// registering handler for error reporting
peer.internals.regHandler.forParticle(particle.id, def.names.errorHandlingSrv, def.names.errorFnName, (req) => {
const [err, _] = req.args;
setTimeout(() => {
reject(err);
}, 0);
return {
retCode: ResultCodes.success,
result: {},
};
});
// registering handler for particle timeout
peer.internals.regHandler.timeout(particle.id, () => {
reject(`Request timed out for ${def.functionName}`);
});
peer.internals.initiateParticle(particle);
});
// if the function has void type we should resolve immediately for API symmetry with non-void types
// to help with debugging we are returning a promise which can be used to track particle errors
// we cannot return a bare promise because JS will lift it, so returning an array with the promise
if (def.returnType.tag === 'void') {
return Promise.resolve([promise]);
} else {
return promise;
}
}
/**
* Convenience function to support Aqua `service` generation backend
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script
*
* @param args - raw arguments passed by user to the generated function
* @param def - service definition generated by the Aqua compiler
*/
export function registerService(args: any[], def: ServiceDef) {
const { peer, service, serviceId } = extractRegisterServiceArgs(args, def.defaultServiceId);
// Checking for missing keys
const requiredKeys = def.functions.map((x) => x.functionName);
const incorrectServiceDefinitions = Object.keys(service).filter((f) => !(f in requiredKeys));
if (!!incorrectServiceDefinitions.length) {
throw new Error(
`Error registering service ${serviceId}: missing functions: ` +
incorrectServiceDefinitions.map((d) => "'" + d + "'").join(', '),
);
}
for (let singleFunction of def.functions) {
// The function has type of (arg1, arg2, arg3, ... , callParams) => CallServiceResultType | void
const userDefinedHandler = service[singleFunction.functionName];
peer.internals.regHandler.common(serviceId, singleFunction.functionName, async (req) => {
const args = convertArgsFromReqToUserCall(req, singleFunction.argDefs);
const rawResult = await userDefinedHandler.apply(null, args);
const result = match(singleFunction.returnType)
.with({ tag: 'primitive' }, () => rawResult)
.with({ tag: 'optional' }, () => tsToAquaOpt(rawResult))
.with({ tag: 'void' }, () => ({}))
.exhaustive();
return {
retCode: ResultCodes.success,
result: result,
};
});
}
}
/**
* Converts argument from ts representation (value | null) to air representation ([value] | [])
*/
const tsToAquaOpt = (arg: unknown | null): any => {
return arg === null || arg === undefined ? [] : [arg];
};
/**
* Converts argument from air representation ([value] | []) to ts representation (value | null)
*/
const aquaOptToTs = (opt: Array<unknown>) => {
return opt.length === 0 ? null : opt[0];
};
/**
* Converts raw arguments which may contain optional types from air representation to ts representation
*/
const convertArgsFromReqToUserCall = (req: CallServiceData, argDefs: Array<ArgDef<OptionalType | PrimitiveType>>) => {
if (req.args.length !== argDefs.length) {
throwForReq(req, `incorrect number of arguments, expected ${argDefs.length}`);
}
const argsAccountedForOptional = req.args.map((x, index) => {
return match(argDefs[index].argType)
.with({ tag: 'optional' }, () => aquaOptToTs(x))
.with({ tag: 'primitive' }, () => x)
.exhaustive();
});
return [...argsAccountedForOptional, extractCallParams(req, argDefs)];
};
/**
* Extracts Call Params from CallServiceData and forms tetraplets according to generated function definition
*/
const extractCallParams = (
req: CallServiceData,
argDefs: Array<ArgDef<OptionalType | PrimitiveType>>,
): CallParams<any> => {
let tetraplets: { [key in string]: SecurityTetraplet[] } = {};
for (let i = 0; i < req.args.length; i++) {
if (argDefs[i]) {
tetraplets[argDefs[i].name] = req.tetraplets[i];
}
}
const callParams = {
...req.particleContext,
tetraplets,
};
return callParams;
};
/**
* Arguments could be passed in one these configurations:
* [...actualArgs]
* [peer, ...actualArgs]
* [...actualArgs, config]
* [peer, ...actualArgs, config]
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, config, args }
*/
const extractFunctionArgs = (
args: any[],
numberOfExpectedArgs: number,
): {
peer: FluencePeer;
config?: { ttl?: number };
args: any[];
} => {
let peer: FluencePeer;
let structuredArgs: any[];
let config: any;
if (FluencePeer.isInstance(args[0])) {
peer = args[0];
structuredArgs = args.slice(1, numberOfExpectedArgs + 1);
config = args[numberOfExpectedArgs + 2];
} else {
peer = Fluence.getPeer();
structuredArgs = args.slice(0, numberOfExpectedArgs);
config = args[numberOfExpectedArgs + 1];
}
return {
peer: peer,
config: config,
args: structuredArgs,
};
};
/**
* Arguments could be passed in one these configurations:
* [serviceObject]
* [peer, serviceObject]
* [defaultId, serviceObject]
* [peer, defaultId, serviceObject]
*
* Where serviceObject is the raw object with function definitions passed by user
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, serviceId, service }
*/
const extractRegisterServiceArgs = (
args: any[],
defaultServiceId?: string,
): { peer: FluencePeer; serviceId: string; service: any } => {
let peer: FluencePeer;
let serviceId: any;
let service: any;
if (FluencePeer.isInstance(args[0])) {
peer = args[0];
} else {
peer = Fluence.getPeer();
}
if (typeof args[0] === 'string') {
serviceId = args[0];
} else if (typeof args[1] === 'string') {
serviceId = args[1];
} else {
serviceId = defaultServiceId;
}
// Figuring out which overload is the service.
// If the first argument is not Fluence Peer and it is an object, then it can only be the service def
// If the first argument is peer, we are checking further. The second argument might either be
// an object, that it must be the service object
// or a string, which is the service id. In that case the service is the third argument
if (!FluencePeer.isInstance(args[0]) && typeof args[0] === 'object') {
service = args[0];
} else if (typeof args[1] === 'object') {
service = args[1];
} else {
service = args[2];
}
return {
peer: peer,
serviceId: serviceId,
service: service,
};
};
function throwForReq(req: CallServiceData, message: string) {
throw new Error(`${message}, serviceId='${req.serviceId}' fnName='${req.fnName}' args='${req.args}'`);
}

View File

@ -1,97 +0,0 @@
import { encode, decode } from 'bs58';
import {
CallServiceData,
CallServiceHandler,
CallServiceResult,
CallServiceResultType,
Middleware,
} from './CallServiceHandler';
import { errorHandler } from './defaultMiddlewares';
const makeDefaultClientHandler = (): CallServiceHandler => {
const success = (resp: CallServiceResult, result: CallServiceResultType) => {
resp.retCode = 0;
resp.result = result;
};
const error = (resp: CallServiceResult, errorMsg: string) => {
resp.retCode = 1;
resp.result = errorMsg;
};
const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => {
if (req.serviceId === 'op') {
switch (req.fnName) {
case 'noop':
success(resp, {});
return;
case 'array':
success(resp, req.args);
return;
case 'identity':
if (req.args.length > 1) {
error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`);
} else {
success(resp, req.args.length === 0 ? {} : req.args[0]);
}
return;
case 'concat':
const incorrectArgIndices = req.args //
.map((x, i) => [Array.isArray(x), i])
.filter(([isArray, _]) => !isArray)
.map(([_, index]) => index);
if (incorrectArgIndices.length > 0) {
const str = incorrectArgIndices.join(', ');
error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`);
} else {
success(resp, [].concat.apply([], req.args));
}
return;
case 'string_to_b58':
if (req.args.length !== 1) {
error(resp, 'string_to_b58 accepts only one string argument');
} else {
success(resp, encode(new TextEncoder().encode(req.args[0])));
}
return;
case 'string_from_b58':
if (req.args.length !== 1) {
error(resp, 'string_from_b58 accepts only one string argument');
} else {
success(resp, new TextDecoder().decode(decode(req.args[0])));
}
return;
case 'bytes_to_b58':
if (req.args.length !== 1 || !Array.isArray(req.args[0])) {
error(resp, 'bytes_to_b58 accepts only single argument: array of numbers');
} else {
const argumentArray = req.args[0] as number[];
success(resp, encode(new Uint8Array(argumentArray)));
}
return;
case 'bytes_from_b58':
if (req.args.length !== 1) {
error(resp, 'bytes_from_b58 accepts only one string argument');
} else {
success(resp, Array.from(decode(req.args[0])));
}
return;
}
}
next();
};
const res = new CallServiceHandler();
res.use(errorHandler);
res.use(mw);
return res;
};
export default makeDefaultClientHandler;

View File

@ -1,14 +0,0 @@
import { CallServiceArg, CallServiceData, CallServiceResult, Middleware, ResultCodes } from './CallServiceHandler';
/**
* Error catching middleware
*/
export const errorHandler: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function): void => {
try {
next();
} catch (e) {
resp.retCode = ResultCodes.exceptionInHandler;
resp.result = `Handler failed. fnName="${req.fnName}" serviceId="${req.serviceId}" error: ${e.toString()}`;
}
};
1;

View File

@ -0,0 +1,106 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CallServiceResult } from '@fluencelabs/avm';
import { encode, decode } from 'bs58';
import { GenericCallServiceHandler, ResultCodes } from './commonTypes';
const success = (result: any): CallServiceResult => {
return {
result: result,
retCode: ResultCodes.success,
};
};
const error = (error: string): CallServiceResult => {
return {
result: error,
retCode: ResultCodes.unknownError,
};
};
export const defaultServices: { [serviceId in string]: { [fnName in string]: GenericCallServiceHandler } } = {
op: {
noop: (req) => {
return success({});
},
array: (req) => {
return success(req.args);
},
identity: (req) => {
if (req.args.length > 1) {
return error(`identity accepts up to 1 arguments, received ${req.args.length} arguments`);
} else {
return success(req.args.length === 0 ? {} : req.args[0]);
}
},
concat: (req) => {
const incorrectArgIndices = req.args //
.map((x, i) => [Array.isArray(x), i])
.filter(([isArray, _]) => !isArray)
.map(([_, index]) => index);
if (incorrectArgIndices.length > 0) {
const str = incorrectArgIndices.join(', ');
return error(`All arguments of 'concat' must be arrays: arguments ${str} are not`);
} else {
return success([].concat.apply([], req.args));
}
},
string_to_b58: (req) => {
if (req.args.length !== 1) {
return error('string_to_b58 accepts only one string argument');
} else {
return success(encode(new TextEncoder().encode(req.args[0])));
}
},
string_from_b58: (req) => {
if (req.args.length !== 1) {
return error('string_from_b58 accepts only one string argument');
} else {
return success(new TextDecoder().decode(decode(req.args[0])));
}
},
bytes_to_b58: (req) => {
if (req.args.length !== 1 || !Array.isArray(req.args[0])) {
return error('bytes_to_b58 accepts only single argument: array of numbers');
} else {
const argumentArray = req.args[0] as number[];
return success(encode(new Uint8Array(argumentArray)));
}
},
bytes_from_b58: (req) => {
if (req.args.length !== 1) {
return error('bytes_from_b58 accepts only one string argument');
} else {
return success(Array.from(decode(req.args[0])));
}
},
},
peer: {
identify: (req) => {
return error('The JS implementation of Peer does not support identify');
},
},
};

View File

@ -1,29 +0,0 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface ModuleConfig {
name: string;
mem_pages_count?: number;
logger_enabled?: boolean;
wasi?: Wasi;
mounted_binaries?: object;
}
export interface Wasi {
envs?: object;
preopened_files?: string[];
mapped_dirs?: object;
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { v4 as uuidv4 } from 'uuid';
import { fromByteArray, toByteArray } from 'base64-js';
import PeerId from 'peer-id';
import { encode } from 'bs58';
import log, { LogLevel } from 'loglevel';
export interface Particle {
id: string;
init_peer_id: string;
timestamp: number;
ttl: number;
script: string;
// sign upper fields
signature: string;
data: Uint8Array;
}
export const logParticle = (fn: Function, message: string, particle: Particle) => {
const toLog = { ...particle };
delete toLog.data;
fn(message, toLog);
};
/**
* Represents particle action to send to a node
*/
interface ParticlePayload {
action: 'Particle';
id: string;
init_peer_id: string;
timestamp: number;
ttl: number;
script: string;
signature: number[];
data: string;
}
/**
* Creates an action to send to a node.
*/
export function toPayload(particle: Particle): ParticlePayload {
return {
action: 'Particle',
id: particle.id,
init_peer_id: particle.init_peer_id,
timestamp: particle.timestamp,
ttl: particle.ttl,
script: particle.script,
// TODO: copy signature from a particle after signatures will be implemented on nodes
signature: [],
data: fromByteArray(particle.data),
};
}
export function parseParticle(str: string): Particle {
let json = JSON.parse(str);
return {
id: json.id,
init_peer_id: json.init_peer_id,
timestamp: json.timestamp,
ttl: json.ttl,
script: json.script,
signature: json.signature,
data: toByteArray(json.data),
};
}
export function genUUID() {
return uuidv4();
}

View File

@ -1,9 +1,26 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AirInterpreter, LogLevel as AvmLogLevel } from '@fluencelabs/avm';
import log from 'loglevel';
import { CallServiceData, CallServiceResult, CallServiceResultType, ResultCodes } from './commonTypes';
import { AvmLoglevel, FluencePeer } from './FluencePeer';
import { RequestFlowBuilder } from './RequestFlowBuilder';
import { Particle } from './Particle';
export const createInterpreter = (handler, peerId, logLevel: AvmLoglevel): Promise<AirInterpreter> => {
export const createInterpreter = (logLevel: AvmLoglevel): Promise<AirInterpreter> => {
const logFn = (level: AvmLogLevel, msg: string) => {
switch (level) {
case 'error':
@ -24,7 +41,16 @@ export const createInterpreter = (handler, peerId, logLevel: AvmLoglevel): Promi
break;
}
};
return AirInterpreter.create(handler, peerId, logLevel, logFn);
return AirInterpreter.create(logLevel, logFn);
};
export const MakeServiceCall = (fn: (args: any[]) => CallServiceResultType) => {
return (req: CallServiceData): CallServiceResult => {
return {
retCode: ResultCodes.success,
result: fn(req.args),
};
};
};
/**
@ -37,23 +63,72 @@ export const checkConnection = async (peer: FluencePeer, ttl?: number): Promise<
}
const msg = Math.random().toString(36).substring(7);
const callbackFn = 'checkConnection';
const callbackService = '_callback';
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`(seq
(call init_relay ("op" "identity") [msg] result)
(call %init_peer_id% ("${callbackService}" "${callbackFn}") [result])
)`,
const promise = new Promise<string>((resolve, reject) => {
const script = `
(xor
(seq
(call %init_peer_id% ("load" "relay") [] init_relay)
(seq
(call %init_peer_id% ("load" "msg") [] msg)
(seq
(call init_relay ("op" "identity") [msg] result)
(call %init_peer_id% ("callback" "callback") [result])
)
)
)
.withTTL(ttl)
.withVariables({
msg,
})
.buildAsFetch<[string]>(callbackService, callbackFn);
(seq
(call init_relay ("op" "identity") [])
(call %init_peer_id% ("callback" "error") [%last_error%])
)
)`;
const particle = Particle.createNew(script, ttl);
peer.internals.regHandler.forParticle(
particle.id,
'load',
'relay',
MakeServiceCall(() => {
return peer.getStatus().relayPeerId;
}),
);
await peer.internals.initiateFlow(request);
peer.internals.regHandler.forParticle(
particle.id,
'load',
'msg',
MakeServiceCall(() => {
return msg;
}),
);
peer.internals.regHandler.forParticle(
particle.id,
'callback',
'callback',
MakeServiceCall((args) => {
const [val] = args;
setTimeout(() => {
resolve(val);
}, 0);
return {};
}),
);
peer.internals.regHandler.forParticle(
particle.id,
'callback',
'error',
MakeServiceCall((args) => {
const [error] = args;
setTimeout(() => {
reject(error);
}, 0);
return {};
}),
);
peer.internals.initiateParticle(particle);
});
try {
const [result] = await promise;
@ -67,6 +142,6 @@ export const checkConnection = async (peer: FluencePeer, ttl?: number): Promise<
}
};
export const ParticleDataToString = (data: Uint8Array): string => {
export function dataToString(data: Uint8Array) {
return new TextDecoder().decode(Buffer.from(data));
};
}