@ -3,8 +3,6 @@ branches:
|
||||
except:
|
||||
- debug
|
||||
node_js:
|
||||
- 4
|
||||
- 6
|
||||
- 8
|
||||
- 10
|
||||
cache:
|
||||
|
115
README.md
@ -1,7 +1,4 @@
|
||||
<p>
|
||||
<a href="https://gun.eco/"><img width="40%" src="https://cldup.com/TEy9yGh45l.svg"/></a>
|
||||
<img width="50%" align="right" vspace="25" src="https://gun.eco/see/demo.gif"/>
|
||||
</p>
|
||||
<p><a href="https://gun.eco/"><img width="40%" src="https://cldup.com/TEy9yGh45l.svg"/></a><img width="50%" align="right" vspace="25" src="https://gun.eco/see/demo.gif"/></p>
|
||||
|
||||
[](https://www.npmjs.com/package/gun)
|
||||
[](https://travis-ci.org/amark/gun)
|
||||
@ -9,7 +6,9 @@
|
||||
[](https://gitter.im/amark/gun)
|
||||
[](https://www.jsdelivr.com/package/npm/gun)
|
||||
|
||||
GUN is a realtime, distributed, offline-first, graph database engine. Doing **[20M+](https://github.com/amark/gun/wiki/100000-ops-sec-in-IE6-on-2GB-Atom-CPU) ops/sec** in just **~9KB** gzipped.
|
||||
**GUN** is an _ecosystem_ of tools that let you <u>build tomorrow's dApps, today</u>.
|
||||
|
||||
Decentralized alternatives to [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
@ -22,22 +21,16 @@ GUN is a realtime, distributed, offline-first, graph database engine. Doing **[2
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<a href="https://youtu.be/-i-11T5ZI9o" title="video: 1 minute demo of fault tolerance"><img src="http://img.youtube.com/vi/-i-11T5ZI9o/0.jpg" width="48%" align="left"></a><a href="https://youtu.be/-FN_J3etdvY" title="video: decentralized auto failover"><img src="http://img.youtube.com/vi/-FN_J3etdvY/0.jpg" width="48%"></a>
|
||||
</tr>
|
||||
</table>
|
||||
The ecosystem is one nice stack of technologies that looks like this:
|
||||
|
||||
## Why?
|
||||
<div><img width="48%" src="https://gun.eco/see/stack.png"/>
|
||||
<img width="48%" align="right" src="https://gun.eco/see/layers.png"/></div>
|
||||
|
||||
- **Realtime** - You might use Socket.IO for realtime updates, but what happens if you reload the page? GUN solves *state synchronization* for you, no matter what, on reloads, across all your users, and even on conflicting updates.
|
||||
- **Distributed** - GUN is peer-to-peer by design, meaning you have no centralized database server to maintain or that could crash. This lets you sleep through the night without worrying about database DevOps - we call it "NoDB". From there, you can build decentralized, federated, or centralized apps.
|
||||
- **Offline-first** - GUN works even if your internet or cell reception doesn't. Users can still plug away and save data as normal, and then when the network comes back online GUN will automatically synchronize all the changes and handle any conflicts for you.
|
||||
- **Graph** - Most databases force you to bend over backwards to match their storage constraints. But graphs are different, they let you have any data structure you want. Whether that be traditional tables with relations, document oriented trees, or tons of circular references. You choose.
|
||||
For now, it is best to start with GUN and _just use it_ to learn the basics, since it is _**so easy**_: (**or** want to read more? Skip ahead to the "[What is GUN?](#what-is-gun)" section.)
|
||||
|
||||
## Quickstart
|
||||
|
||||
- Try the [interactive tutorial](https://gun.eco/think.html) in the browser (**5min** ~ average developer).
|
||||
- Try the [interactive tutorial](https://gun.eco/docs/Todo-Dapp) in the browser (**5min** ~ average developer).
|
||||
- Or `npm install gun` and run the examples with `cd node_modules/gun && npm start` (**5min** ~ average developer).
|
||||
|
||||
> **Note:** If you don't have [node](http://nodejs.org/) or [npm](https://www.npmjs.com/), read [this](https://github.com/amark/gun/blob/master/examples/install.sh) first.
|
||||
@ -62,7 +55,7 @@ gun.get('mark').on(function(data, key){
|
||||
});
|
||||
</script>
|
||||
```
|
||||
- Or try something mind blowing, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
|
||||
- Or try something **mind blowing**, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
|
||||
```javascript
|
||||
var cat = {name: "Fluffy", species: "kitty"};
|
||||
var mark = {boss: cat};
|
||||
@ -72,7 +65,7 @@ cat.slave = mark;
|
||||
gun.get('mark').put(mark);
|
||||
|
||||
// access the data as if it is a document.
|
||||
gun.get('mark').get('boss').get('name').val(function(data, key){
|
||||
gun.get('mark').get('boss').get('name').once(function(data, key){
|
||||
// `val` grabs the data once, no subscriptions.
|
||||
console.log("Mark's boss is", data);
|
||||
});
|
||||
@ -95,20 +88,32 @@ gun.get('list').map().once(function(data, key){
|
||||
gun.get('list').set({type: "cucumber", goal: "scare cat"});
|
||||
```
|
||||
|
||||
## Support
|
||||
Want to keep building more? **Jump to [THE DOCUMENTATION](#documentation)!**
|
||||
|
||||
# What is GUN?
|
||||
|
||||
First & foremost, GUN is **a community of the nicest and most helpful people** out there. So [I want to invite you](https://gitter.im/amark/gun) to come tell us about what **you** are working on & wanting to build (new or old school alike! Just be nice as well.) and ask us your questions directly. :)
|
||||
|
||||
On that note, let's get some official shout outs covered first:
|
||||
|
||||
### Support
|
||||
|
||||
<p align="center">
|
||||
Thanks to:<br/>
|
||||
<a href="http://qxip.net/">Lorenzo Mangani</a>,
|
||||
<a href="http://github.com/samliu">Sam Liu</a>,
|
||||
<a href="http://github.com/ddombrow">Daniel Dombrowsky</a>,
|
||||
<a href="http://github.com/vincentwoo">Vincent Woo</a>,
|
||||
<a href="http://github.com/coolaj86">AJ ONeal</a>,
|
||||
<a href="https://github.com/robertheessels">Robert Heessels</a>,
|
||||
<a href="http://qxip.net/">Lorenzo Mangani</a>,
|
||||
<a href="https://nlnet.nl/">NLnet Foundation</a>,
|
||||
<a href="http://github.com/samliu">Sam Liu</a>,
|
||||
<a href="http://github.com/ddombrow">Daniel Dombrowsky</a>,
|
||||
<a href="http://github.com/vincentwoo">Vincent Woo</a>,
|
||||
<a href="http://github.com/coolaj86">AJ ONeal</a>,
|
||||
<a href="http://github.com/ottman">Bill Ottman</a>,
|
||||
<a href="http://github.com/ctrlplusb">Sean Matheson</a>,
|
||||
<a href="http://github.com/mikewlange">Mike Lange</a>,
|
||||
<a href="http://github.com/ctrlplusb">Sean Matheson</a>,
|
||||
<a href="http://github.com/alanmimms">Alan Mimms</a>,
|
||||
<a href="https://github.com/dfreire">Dário Freire</a>,
|
||||
<a href="http://github.com/velua">John Williamson</a>
|
||||
<a href="http://github.com/velua">John Williamson</a>,
|
||||
<a href="http://github.com/finwo">Robin Bron</a>
|
||||
</p>
|
||||
|
||||
- Join others in sponsoring code: https://www.patreon.com/gunDB !
|
||||
@ -116,13 +121,26 @@ Thanks to:<br/>
|
||||
- Found a bug? Report at: https://github.com/amark/gun/issues ;
|
||||
- **Need help**? Chat with us: https://gitter.im/amark/gun .
|
||||
|
||||
### History
|
||||
|
||||
[GUN](https://gun.eco) was created by [Mark Nadal](https://twitter.com/marknadal) in 2014 after he had spent 4 years trying to get his collaborative web app to scale up with traditional databases.
|
||||
|
||||
<img width="250px" src="https://gun.eco/see/problem.png" align="left" title="pain point" style="margin: 0 1em 1em 0"> After he realized [Master-Slave database architecture causes one big bottleneck](https://gun.eco/distributed/matters.html), he (as a complete newbie outsider) naively decided **to question the status quo** and shake things up with controversial, heretical, and contrarian experiments:
|
||||
|
||||
**The NoDB** - no master, no servers, no "single source of truth", not built with a real programming language or real hardware, no DevOps, no locking, not *just* SQL or NoSQL but both (**all** - graphs, documents, tables, key/value).
|
||||
|
||||
The goal was to build a P2P database that could survive living inside **any** browser, and could correctly sync data between **any** device after assuming **any** offline-first activity.
|
||||
|
||||
<img src="https://gun.eco/see/compare.png" title="comparison table">
|
||||
|
||||
Technically, **GUN is a graph synchronization protocol** with a *lightweight embedded engine*, capable of doing *[20M+ API ops/sec](https://gun.eco/docs/Performance)* in **just ~9KB gzipped size**.
|
||||
|
||||
## Documentation
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/API">API reference</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/think.html">Tutorials</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/API">API reference</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/Todo-Dapp">Tutorials</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/tree/master/examples">Examples</a></h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -136,23 +154,52 @@ Thanks to:<br/>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/Stefdv/gun-ui-lcd#syncing">Webcomponents</a></h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/CAP-Theorem">CAP Theorem Tradeoffs</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/CAP-Theorem">CAP Theorem Tradeoffs</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/distributed/matters.html">How Data Sync Works</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/porting-gun">How GUN is Built</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/Porting-GUN">How GUN is Built</a></h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/auth">Crypto Auth</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/Modules">Modules</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://github.com/amark/gun/wiki/roadmap">Roadmap</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/Auth">Crypto Auth</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/Awesome-GUN">Modules</a></h3></td>
|
||||
<td style="border: 0;"><h3><a href="https://gun.eco/docs/Roadmap">Roadmap</a></h3></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This would not be possible without **community contributors**, big shout out to:
|
||||
|
||||
**[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; [sbeleidy](https://github.com/sbeleidy); **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
|
||||
**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
|
||||
|
||||
I am missing many others, apologies, will be adding them soon!
|
||||
|
||||
## Testing
|
||||
|
||||
Tests may be run with `npm test`. Tests will trigger persistent writes to the DB, so subsequent runs of the test will fail. You must clear the DB before running the tests again. This can be done by running the following command in the project directory.
|
||||
|
||||
```bash
|
||||
rm -rf *data*
|
||||
```
|
||||
|
||||
### Additional Cryptography Libraries
|
||||
|
||||
To install with npm, first install `npm install gun -S`.
|
||||
For just the networking layer, import Gun:
|
||||
|
||||
```javascript
|
||||
var Gun = require('gun/gun');
|
||||
```
|
||||
|
||||
If you also need to install SEA for user auth and crypto, also install some of its dependencies like this:
|
||||
|
||||
`npm install @trust/crypto text-encoding node-webcrypto-ossl --save`
|
||||
|
||||
You will need to require it too (it will be automatically added to the Gun object):
|
||||
|
||||
```javascript
|
||||
var Gun = require('gun/gun');
|
||||
var Sea = require('gun/sea');
|
||||
```
|
||||
|
||||
|
||||
## Deploy
|
||||
|
||||
To quickly spin up a Gun test server for your development team, utilize either [Heroku](http://heroku.com) or [Docker](http://docker.com) or any variant thereof [Dokku](http://dokku.viewdocs.io/dokku/), [Flynn.io](http://flynn.io), [now.sh](https://zeit.co/now), etc. !
|
||||
|
11
as.js
@ -80,12 +80,11 @@
|
||||
}, wait || 200);
|
||||
}
|
||||
}
|
||||
as.sort = function(sort, el) {
|
||||
var vs = $(el).find('.sort');
|
||||
vs = (vs[0] && u === vs[0].value)? vs.text() : vs.val();
|
||||
var id = sort;
|
||||
var test = id >= vs;
|
||||
return test ? el : as.sort(sort, el.prev());
|
||||
as.sort = function sort(id, li){
|
||||
var num = parseFloat(id);
|
||||
var id = $(li).find('.sort').text() || -Infinity;
|
||||
var at = num >= parseFloat(id);
|
||||
return at ? li : sort(id, li.prev());
|
||||
}
|
||||
$(document).on('keyup', 'input, textarea, [contenteditable]', as.wait(function(){
|
||||
var el = $(this);
|
||||
|
99
axe.js
Normal file
@ -0,0 +1,99 @@
|
||||
;(function(){
|
||||
|
||||
/* UNBUILD */
|
||||
var root;
|
||||
if(typeof window !== "undefined"){ root = window }
|
||||
if(typeof global !== "undefined"){ root = global }
|
||||
root = root || {};
|
||||
var console = root.console || {log: function(){}};
|
||||
function USE(arg, req){
|
||||
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
||||
arg(mod = {exports: {}});
|
||||
USE[R(path)] = mod.exports;
|
||||
}
|
||||
function R(p){
|
||||
return p.split('/').slice(-1).toString().replace('.js','');
|
||||
}
|
||||
}
|
||||
if(typeof module !== "undefined"){ var common = module }
|
||||
/* UNBUILD */
|
||||
|
||||
;USE(function(module){
|
||||
if(typeof window !== "undefined"){ module.window = window }
|
||||
var tmp = module.window || module;
|
||||
var AXE = tmp.AXE || function(){};
|
||||
|
||||
if(AXE.window = module.window){ try{
|
||||
AXE.window.AXE = AXE;
|
||||
tmp = document.createEvent('CustomEvent');
|
||||
tmp.initCustomEvent('extension', false, false, {type: "AXE"});
|
||||
(window.dispatchEvent || window.fireEvent)(tmp);
|
||||
window.postMessage({type: "AXE"}, '*');
|
||||
} catch(e){} }
|
||||
|
||||
try{ if(typeof common !== "undefined"){ common.exports = AXE } }catch(e){}
|
||||
module.exports = AXE;
|
||||
})(USE, './root');
|
||||
|
||||
;USE(function(module){
|
||||
|
||||
var AXE = USE('./root'), Gun = (AXE.window||{}).Gun || USE('./gun', 1);
|
||||
(Gun.AXE = AXE).GUN = AXE.Gun = Gun;
|
||||
|
||||
Gun.on('opt', function(at){
|
||||
if(!at.axe){
|
||||
at.axe = {};
|
||||
var p = at.opt.peers, tmp;
|
||||
// 1. If any remembered peers or from last cache or extension
|
||||
// 2. Fallback to use hard coded peers from dApp
|
||||
// 3. Or any offered peers.
|
||||
//if(Gun.obj.empty(p)){
|
||||
// Gun.obj.map(['http://localhost:8765/gun'/*, 'https://guntest.herokuapp.com/gun'*/], function(url){
|
||||
// p[url] = {url: url, axe: {}};
|
||||
// });
|
||||
//}
|
||||
// Our current hypothesis is that it is most optimal
|
||||
// to take peers in a common network, and align
|
||||
// them in a line, where you only have left and right
|
||||
// peers, so messages propagate left and right in
|
||||
// a linear manner with reduced overlap, and
|
||||
// with one common superpeer (with ready failovers)
|
||||
// in case the p2p linear latency is high.
|
||||
// Or there could be plenty of other better options.
|
||||
console.log("axe", at.opt);
|
||||
if(at.opt.super){
|
||||
function verify(msg, send, at) {
|
||||
var peers = Object.keys(p), puts = Object.keys(msg.put), i, j, peer;
|
||||
var soul = puts[0]; /// TODO: verify all souls in puts. Copy the msg only with subscribed souls?
|
||||
for (i=0; i < peers.length; ++i) {
|
||||
peer = p[peers[i]];
|
||||
//if (peer.url) {console.log('AXE do not reject superpeers'); send(msg, peer); continue;} /// always send to superpeers?
|
||||
if (!peer.id) {console.log('AXE peer without id: ', peer); continue;}
|
||||
if (!Gun.subscribe[soul] || !Gun.subscribe[soul][peer.id]) { console.log('AXE SAY reject msg to peer: %s, soul: %s', peer.id, soul); continue; }
|
||||
send(msg, peer);
|
||||
}
|
||||
}
|
||||
AXE.say = function(msg, send, at) {
|
||||
if (!msg.put) { send(msg); return; }
|
||||
console.log('AXE HOOK!! ', msg);
|
||||
verify(msg, send, at);
|
||||
};
|
||||
/// TODO: remove peer from all Gun.subscribe. On `mesh.bye` event?
|
||||
}
|
||||
if(at.opt.super){
|
||||
at.on('in', USE('./lib/super', 1), at);
|
||||
} else {
|
||||
//at.on('in', input, at);
|
||||
}
|
||||
}
|
||||
this.to.next(at); // make sure to call the "next" middleware adapter.
|
||||
});
|
||||
|
||||
function input(msg){
|
||||
var at = this.as, to = this.to;
|
||||
}
|
||||
|
||||
module.exports = AXE;
|
||||
})(USE, './axe');
|
||||
|
||||
}());
|
40
examples/axe.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0" />
|
||||
<title>Testing AXE</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="../gun.js"></script>
|
||||
<!-- <script src="../axe.js"></script> -->
|
||||
<!-- <script src="../sea.js"></script> -->
|
||||
<script>
|
||||
var pid = location.hash.slice(1);
|
||||
|
||||
var opt = ({
|
||||
peers: [`${location.origin}/gun`]
|
||||
});
|
||||
|
||||
if (pid) { opt.pid = pid; }
|
||||
|
||||
Gun.on('opt', function(ctx) {
|
||||
this.to.next(ctx);
|
||||
ctx.on('hi', function(opt) {
|
||||
console.log('HI!! PEER', new Date(), opt.pid);
|
||||
});
|
||||
if (pid) {
|
||||
ctx.on('out', function(msg) {
|
||||
msg.pid = pid;
|
||||
this.to.next(msg);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var gun = Gun(opt);
|
||||
//var user = gun.user();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -73,7 +73,6 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/examples/jquery.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/lib/open.js"></script>
|
||||
|
||||
<script>
|
||||
//var gun = Gun();
|
||||
@ -104,7 +103,6 @@ gun.on('auth', function(){
|
||||
$('#profile input').on('keyup', function(e){
|
||||
if(!user.is){ return }
|
||||
var id = LI.busy = $(this).attr('id');
|
||||
console.log("Huh?", id, user);
|
||||
user.get('profile').get(id).secret($(this).val());
|
||||
}).on('blur', function(){ LI.busy = false })
|
||||
|
50
examples/basic/space.html
Normal file
@ -0,0 +1,50 @@
|
||||
<h1>Search</h1>
|
||||
|
||||
<form id="ask">
|
||||
<input id="search" placeholder="search..." autocomplete="off">
|
||||
</form>
|
||||
|
||||
<div id="answer"></div>
|
||||
<ul></ul>
|
||||
|
||||
<small>Note: No data is indexed by default, you need to add some!</small>
|
||||
|
||||
<script src="../../examples/jquery.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
<script src="../../sea.js"></script>
|
||||
<script src="../../lib/space.js"></script>
|
||||
|
||||
<script>
|
||||
var gun = Gun();
|
||||
var ask = {};
|
||||
|
||||
$('#search').on('keyup', function(e){
|
||||
ask.now = (this.value||'').toLowerCase().replace(/[\W_]+/g,"");
|
||||
if(ask.last === ask.now){ return }
|
||||
ask.last = ask.now;
|
||||
clearTimeout(ask.to);
|
||||
ask.to = setTimeout(search, 20);
|
||||
});
|
||||
|
||||
function search(){
|
||||
var key = ask.now;
|
||||
gun.get('Q').space(key, function(ack){
|
||||
if(!ack || key !== ask.now){ return }
|
||||
UI(ack)
|
||||
});
|
||||
}
|
||||
|
||||
function UI(ack){
|
||||
$('#answer').text(ack.data || '');
|
||||
var $ul = $('ul').empty(), tree = ack.tree;
|
||||
Gun.obj.map(tree, function(v,k){
|
||||
$('<li>').text(k +' - ' + v).appendTo($ul);
|
||||
});
|
||||
};
|
||||
|
||||
function load(DATA){
|
||||
Gun.obj.map(DATA, function(v,k){
|
||||
gun.get('Q').space(k, v);
|
||||
});
|
||||
}
|
||||
</script>
|
@ -5,40 +5,42 @@
|
||||
<input id="pass" type="password" placeholder="passphrase">
|
||||
<input id="in" type="submit" value="sign in">
|
||||
<input id="up" type="button" value="sign up">
|
||||
<input id="mask" type="button" value="Identifi Login">
|
||||
</form>
|
||||
|
||||
<ul></ul>
|
||||
|
||||
<form id="said">
|
||||
<input id="say">
|
||||
<input id="speak" type="button" value="speak">
|
||||
<input id="speak" type="submit" value="speak">
|
||||
</form>
|
||||
|
||||
<script src="../../examples/jquery.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
<script src="../../sea.js"></script>
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
<script src="../../../gun/sea.js"></script>
|
||||
|
||||
<script>
|
||||
var gun = Gun();
|
||||
var user = gun.user();
|
||||
var gun = Gun(); //Gun(['http://localhost:8765/gun', 'https://guntest.herokuapp.com/gun']);
|
||||
var user = gun.user().recall({sessionStorage: true});
|
||||
|
||||
$('#up').on('click', function(e){
|
||||
user.create($('#alias').val(), $('#pass').val());
|
||||
user.create($('#alias').val(), $('#pass').val(), login);
|
||||
});
|
||||
|
||||
$('#sign').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
function login(e){
|
||||
user.auth($('#alias').val(), $('#pass').val());
|
||||
});
|
||||
return false; // e.preventDefault();
|
||||
};
|
||||
$('#sign').on('submit', login);
|
||||
$('#mask').on('click', login);
|
||||
|
||||
gun.on('auth', function(){
|
||||
$('#sign').hide();
|
||||
user.get('said').map().val(UI);
|
||||
user.get('said').map().on(UI);
|
||||
});
|
||||
|
||||
$('#said').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
if(!user.is){ return }
|
||||
//if(!user.is){ return }
|
||||
user.get('said').set($('#say').val());
|
||||
$('#say').val("");
|
||||
});
|
@ -2,12 +2,16 @@ console.log("If module not found, install express globally `npm i express -g`!")
|
||||
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765;
|
||||
var express = require('express');
|
||||
var Gun = require('..');
|
||||
require('../axe');
|
||||
|
||||
var app = express();
|
||||
app.use(Gun.serve);
|
||||
app.use(express.static(__dirname));
|
||||
|
||||
var server = app.listen(port);
|
||||
Gun({ file: 'data.json', web: server });
|
||||
var gun = Gun({ file: 'data', web: server });
|
||||
|
||||
global.Gun = Gun; /// make global to `node --inspect` - debug only
|
||||
global.gun = gun; /// make global to `node --inspect` - debug only
|
||||
|
||||
console.log('Server started on port ' + port + ' with /gun');
|
||||
|
@ -7,13 +7,15 @@
|
||||
<div class="laser"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p id="debug" style="position: fixed; bottom: 0px; color: white; height: 1em;"></p>
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
<script src="../../../gun/nts.js"></script>
|
||||
<script src="../../../gun/lib/webrtc.js"></script>
|
||||
<script>
|
||||
// Thanks to https://github.com/dmcinnes/HTML5-Asteroids
|
||||
//var gun = Gun();
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var gun = Gun(location.host? location.origin+'/gun' : 'http://localhost:8765/gun');
|
||||
var game = {gun: gun.get('example/game/space'), area: {}, ships: {}};
|
||||
game.keys = {38: 'up', 37: 'left', 39: 'right', 40: 'down', 32: 'space'};
|
||||
$(document).on('keydown', function(e){
|
||||
@ -178,6 +180,7 @@
|
||||
game.start = function(){
|
||||
game.now = Gun.state();
|
||||
game.resize();
|
||||
game.ship();
|
||||
game.gun.get('players').map().on(function(data, id){
|
||||
data = Gun.obj.copy(data);
|
||||
data.x = data.x * game.area.x;
|
||||
@ -185,7 +188,6 @@
|
||||
data.id = data.id || id;
|
||||
game.ship(data);
|
||||
});
|
||||
game.ship();
|
||||
var frame = game.frame, ships = game.ships;
|
||||
var last = game.now, now, diff, delta;
|
||||
setInterval(game.sync, 99);
|
||||
@ -203,6 +205,27 @@
|
||||
$(function(){
|
||||
game.start();
|
||||
});
|
||||
|
||||
// test WebRTC
|
||||
gun.on('hi', function(peer){
|
||||
console.log("hi!", peer);
|
||||
if(peer.url){ return }
|
||||
Gun.obj.map(gun.back('opt.peers'), function(peer){
|
||||
if(!peer.url || !peer.wire){ return }
|
||||
peer.wire._send = peer.wire.send;
|
||||
peer.wire.send = send;
|
||||
var tmp = 'GOBBLE GOBBLE: Not sending any non-WebRTC messages to ' + peer.url;
|
||||
console.log(tmp);
|
||||
$('#debug').text(tmp);
|
||||
});
|
||||
});
|
||||
function send(raw){
|
||||
if(!raw){ return }
|
||||
if(raw.indexOf('webrtc') >= 0){
|
||||
if(!this._send){ return }
|
||||
return this._send(raw);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
html, body {
|
||||
|
@ -1,20 +1,21 @@
|
||||
var fs = require('fs');
|
||||
var config = {
|
||||
port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765
|
||||
};
|
||||
var Gun = require('../'); // require('gun')
|
||||
;(function(){
|
||||
var cluster = require('cluster');
|
||||
if(cluster.isMaster){
|
||||
return cluster.fork() && cluster.on('exit', function(){ cluster.fork() });
|
||||
}
|
||||
|
||||
if(process.env.HTTPS_KEY){
|
||||
config.key = fs.readFileSync(process.env.HTTPS_KEY);
|
||||
config.cert = fs.readFileSync(process.env.HTTPS_CERT);
|
||||
config.server = require('https').createServer(config, Gun.serve(__dirname));
|
||||
} else {
|
||||
config.server = require('http').createServer(Gun.serve(__dirname));
|
||||
}
|
||||
var fs = require('fs');
|
||||
var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 };
|
||||
var Gun = require('../'); // require('gun')
|
||||
|
||||
var gun = Gun({
|
||||
web: config.server
|
||||
});
|
||||
if(process.env.HTTPS_KEY){
|
||||
config.key = fs.readFileSync(process.env.HTTPS_KEY);
|
||||
config.cert = fs.readFileSync(process.env.HTTPS_CERT);
|
||||
config.server = require('https').createServer(config, Gun.serve(__dirname));
|
||||
} else {
|
||||
config.server = require('http').createServer(Gun.serve(__dirname));
|
||||
}
|
||||
|
||||
config.server.listen(config.port);
|
||||
console.log('Server started on port ' + config.port + ' with /gun');
|
||||
var gun = Gun({web: config.server.listen(config.port) });
|
||||
console.log('Relay peer started on port ' + config.port + ' with /gun');
|
||||
}());
|
210
examples/move/index.html
Normal file
@ -0,0 +1,210 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
HELP WANTED!
|
||||
Build decentralized Open Source Uber/Lyft!
|
||||
Need people with experience on:
|
||||
- Leaflet API, zoom and tile coordinates for subscribing to surrounding area.
|
||||
- Creating cute little driving icons that animate with heading/direction.
|
||||
-->
|
||||
<title>Move by Neon ERA</title>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.0.3/dist/leaflet.css"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.0.3/dist/leaflet.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<a id="share" class="hide"><div class="stick button">Request Ride</div></a>
|
||||
<div id="link" class="hide">
|
||||
<p>Copy and Paste this URL to your friends to share your location:</p>
|
||||
<center>
|
||||
<p id="follow">Location sharing not available!</p>
|
||||
</center>
|
||||
<p><b>Note</b>: Location may not sync when your device's screen is off or the tab is out of focus. You'd need to install this as an app for that to work.</p>
|
||||
<center>
|
||||
<a id="close"><div class="button">Close</div></a>
|
||||
</center>
|
||||
</div>
|
||||
<textarea style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 5em;" id="debug"></textarea>
|
||||
<style>
|
||||
html, body, #map {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: Arial;
|
||||
font-size: 16pt;
|
||||
z-index: 1;
|
||||
}
|
||||
.stick {
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
right: 1em;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
opacity: .5;
|
||||
background: blue;
|
||||
color: white;
|
||||
z-index: 7;
|
||||
transition: .25s all;
|
||||
}
|
||||
.button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
#link {
|
||||
position: absolute;
|
||||
padding: 1em;
|
||||
top: 2em;
|
||||
left: 2em;
|
||||
right: 2em;
|
||||
bottom: 2em;
|
||||
background: white;
|
||||
overflow: scroll;
|
||||
z-index: 9;
|
||||
}
|
||||
#follow {
|
||||
background: #EEE;
|
||||
padding: .5em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script>
|
||||
function Where(opt, cb){
|
||||
// a small wrapper around Leaflet for map tracking.
|
||||
var where = {};
|
||||
where.opt = opt || {};
|
||||
where.opt.zoom = where.opt.zoom || {};
|
||||
where.opt.err = where.opt.err || function(){};
|
||||
|
||||
where.map = L.map('map', { zoom: where.opt.zoom.level });
|
||||
|
||||
where.opt.tile = where.opt.tile || L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: where.opt.zoom.max,
|
||||
minZoom: where.opt.zoom.min,
|
||||
detectRetina: true,
|
||||
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
||||
});
|
||||
where.map.addLayer(where.opt.tile);
|
||||
|
||||
L.GridLayer.DebugCoords = L.GridLayer.extend({
|
||||
createTile: function (coords) {
|
||||
var tile = document.createElement('div');
|
||||
tile.innerHTML = [coords.z, coords.x, coords.y].join(', ');
|
||||
tile.style.outline = '1px solid black';
|
||||
return tile;
|
||||
}
|
||||
});
|
||||
L.gridLayer.debugCoords = function(opts) {
|
||||
return new L.GridLayer.DebugCoords(opts);
|
||||
};
|
||||
where.map.addLayer( L.gridLayer.debugCoords() );
|
||||
|
||||
where.opt.zoom.ing = where.opt.zoom.ing || function(){
|
||||
where.opt.zoom.level = where.map.getZoom();
|
||||
}
|
||||
where.map.on('zoomstart', where.opt.zoom.ing, where.opt.err);
|
||||
where.map.on('zoomend', where.opt.zoom.ing, where.opt.err);
|
||||
where.map.on('zoomlevelschange', where.opt.zoom.ing, where.opt.err);
|
||||
|
||||
where.update = function(latlng){
|
||||
if((+new Date) - where.update.last < 400){
|
||||
clearTimeout(where.update.to);
|
||||
where.update.to = setTimeout(function(){
|
||||
where.update(latlng);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var z = 12;
|
||||
var x = lng2tile(latlng.lng, z);
|
||||
var y = lat2tile(latlng.lat, z);
|
||||
console.log(x, y); //
|
||||
where.map.setView(latlng, where.opt.zoom.level, {animate: true});
|
||||
where.marker = where.marker || L.marker().setLatLng(latlng).addTo(where.map);
|
||||
where.marker.setLatLng(latlng).update();
|
||||
where.update.last = (+new Date);
|
||||
}
|
||||
|
||||
if(where.opt.track){
|
||||
where.map.on('locationfound', function(pos){
|
||||
where.update(pos.latlng);
|
||||
where.opt.track(pos);
|
||||
});
|
||||
|
||||
where.map.locate({
|
||||
setView: true,
|
||||
zoom: where.opt.zoom.level,
|
||||
watch: where.opt.continuous || true,
|
||||
timeout: where.opt.timeout || 10000,
|
||||
maximumAge: where.opt.maximumAge || 0,
|
||||
enableHighAccuracy: where.opt.enableHighAccuracy || false
|
||||
});
|
||||
}
|
||||
|
||||
function lng2tile(lng,z) { return (Math.floor((lng+180)/360*Math.pow(2,z))) }
|
||||
function lat2tile(lat,z) { return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,z))) }
|
||||
|
||||
return where;
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
;(function(){
|
||||
// the actual GPS tracking app!
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var gps = {};
|
||||
gps.opt = {
|
||||
continuous: true, // get location just once uses `getCurrentPosition()` while continuously uses `watchPosition()`
|
||||
enableHighAccuracy: true, // HighAccuracy uses more resources, https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions
|
||||
timeout: 5000, // have this long to get data before erring.
|
||||
maximumAge: 0, // set to 0 to actually track.
|
||||
zoom: {max: 18, level: 13, min: 12}
|
||||
}
|
||||
function start(){
|
||||
gps.follow = (window.location.hash || '').slice(1);
|
||||
if(gps.follow){
|
||||
gps.where = gps.where || Where(gps.opt);
|
||||
gps.ref = gun.get('gps/' + gps.follow);
|
||||
gps.ref.on(function(latlng){
|
||||
//$('#debug').value = 'track ' + JSON.stringify(latlng);
|
||||
gps.where.update(latlng);
|
||||
});
|
||||
$('#share').addClass("hide");
|
||||
} else {
|
||||
document.cookie = 'gps=' + (gps.track = (document.cookie.match(/gps\=(.*?)(\&|$|\;)/i)||[])[1] || Gun.text.random(5)); // trick with cookies!
|
||||
gps.ref = gun.get('gps/' + gps.track);
|
||||
gps.opt.track = function(pos){
|
||||
pos = pos.latlng;
|
||||
if(gps.follow
|
||||
|| Gun.time.is() - gps.when < 1000
|
||||
|| gps.last && gps.last.lat == pos.lat && gps.last.lng == pos.lng){
|
||||
return; // throttle!
|
||||
}
|
||||
gps.when = Gun.time.is();
|
||||
gps.ref.put(gps.last = pos);
|
||||
//$('#debug').value = JSON.stringify(gps.last);
|
||||
}
|
||||
gps.where = gps.where || Where(gps.opt);
|
||||
$('#follow').text(("where.gunDB.io/" || (location.origin + location.pathname)) + '#' + gps.track);
|
||||
$('#share').removeClass("hide");
|
||||
$('#share').on('click', function(){
|
||||
$('#link').toggleClass("hide");
|
||||
});
|
||||
$('#close').on('click', function(){
|
||||
$('#link').toggleClass("hide");
|
||||
});
|
||||
}
|
||||
}
|
||||
start();
|
||||
window.onhashchange = start;
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Party by Neon ERA</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic" rel="stylesheet" type="text/css">
|
||||
@ -37,10 +38,12 @@
|
||||
;(() => {
|
||||
function S(){};
|
||||
window.S = S;
|
||||
try{localStorage.clear();//sessionStorage.clear();
|
||||
}catch(e){}
|
||||
S.gun = Gun(location.host? location.origin+'/gun' : 'http://localhost:8765/gun');
|
||||
//S.gun = Gun('http://localhost:8765/gun');
|
||||
//S.gun = Gun();
|
||||
S.app = S.gun.get('examples/social/1');
|
||||
S.app = S.gun.get('examples/social/2');
|
||||
S.user = S.gun.user();
|
||||
S.tell = (what, n) => {
|
||||
var e = $('#tell').find('p');
|
||||
@ -68,7 +71,7 @@
|
||||
width: 3em;
|
||||
}
|
||||
</style>
|
||||
<div class="loud write shout rim">A social network you own & control.</div>
|
||||
<div class="loud write shout rim">Party by NEON ERA.</div>
|
||||
<div id="faces" class="flush faces">
|
||||
<div class="right" style="max-width: 20em;">
|
||||
<input id="halias" class="write jot sap" placeholder="username">
|
||||
@ -508,6 +511,8 @@
|
||||
}
|
||||
#draft .what {
|
||||
}
|
||||
#draft .spoke {
|
||||
}
|
||||
</style>
|
||||
<p class="pad">Welcome!</p>
|
||||
<!--
|
||||
@ -520,14 +525,14 @@
|
||||
- take
|
||||
-->
|
||||
<form id="speak" class="mid row col">
|
||||
<div id="d0" class="draft gap tint sap" contenteditable="true" style="min-height: 1em;" data-text="Express yourself..."></div>
|
||||
<div id="d0" class="draft spoke gap tint sap editable" contenteditable="true" style="min-height: 1em;" data-text="Express yourself..."></div>
|
||||
<input type="submit" class="sap hide" value="speak!">
|
||||
</form>
|
||||
<ul class="mid row col">
|
||||
</ul>
|
||||
<div class="model">
|
||||
<li class="spoke tint sap gully">
|
||||
<div class="gap"><img class="face act none"><b class="name"></b><span class="what"></span></div>
|
||||
<div class="gap"><span class="sort none"></span><img class="face act none"><b class="name"></b><div class="what"></div></div>
|
||||
</li>
|
||||
</div>
|
||||
<div style="height: 10%;"></div>
|
||||
@ -544,26 +549,40 @@
|
||||
});
|
||||
window.user = S.user;
|
||||
$('#speak').on('submit', (e) => {
|
||||
var say = $('#speak .draft').text();
|
||||
var say = $('#speak .draft').text(); //.text(); // NO NO NO NO NO
|
||||
if(!say){ return }
|
||||
var ref = S.user.get('who').get('all').set({what: say});
|
||||
ref.get('by').put(S.user.get('who'));
|
||||
S.user.get('who').get('said').time(ref);
|
||||
S.gun.get('@').time(ref);
|
||||
console.log('save!', say);
|
||||
var ref = S.user.get('who').get('all').set({what: say, when: Gun.state()});
|
||||
//ref.get('by').put(S.user.get('who'));
|
||||
//S.user.get('who').get('said').time(ref);
|
||||
S.user.get('who').get('said').set(ref);
|
||||
//S.gun.get('@').time(ref);
|
||||
$('#speak .draft').text('');
|
||||
});
|
||||
S.gun.get('@').time(async (data, key, time) => {
|
||||
var ref = S.gun.get(data);
|
||||
var said = await ref.then();
|
||||
var $li = $($('#'+key)[0] || $('#draft .model .spoke').clone(true,true).attr('id', key).prependTo('#draft ul'));
|
||||
$li.find('.what').text(said.what);
|
||||
var by = ref.get('by');
|
||||
//S.gun.get('@').time(async (data, key, time) => {
|
||||
S.user.get('who').get('said').map().once(async (data, key, time) => {
|
||||
//var ref = S.gun.get(data), tmp;
|
||||
//var said = await ref.then();
|
||||
key = key.replace(/[^A-Za-z]/ig,'');
|
||||
var tmp, said = data, time = said.when;
|
||||
var $li = $($('#'+key)[0] || $('#draft .model .spoke').clone(true,true).attr('id', key)[(tmp = $.as.sort(time, $('#draft ul').children('li').first()))[0]?'insertBefore':'appendTo'](tmp[0] || '#draft ul'));
|
||||
tmp = said.what;
|
||||
if(tmp && tmp.ct){
|
||||
tmp = JSON.stringify(tmp);
|
||||
setTimeout(async function(){
|
||||
tmp = await SEA.decrypt(said.what, S.user._.sea);
|
||||
$li.find('.what').text(tmp);
|
||||
}, 750);
|
||||
}
|
||||
$li.find('.what').text(tmp); // NORMALIAZE!!!
|
||||
var by = S.user.get('who');// ref.get('by');
|
||||
by.get('face').get('small').on(data => {
|
||||
$li.find('.face').attr('src', data).removeClass('none');
|
||||
});
|
||||
by.get('name').on(data => {
|
||||
data && $li.find('b').text(data);
|
||||
});
|
||||
$li.find('.sort').text(time);
|
||||
var time = new Date(time);
|
||||
$li.find('i').text(time.toDateString() + ', ' + time.toLocaleTimeString());
|
||||
return;
|
||||
@ -572,7 +591,7 @@
|
||||
if(face){
|
||||
$li.find('.face').attr('src', face).removeClass('none');
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
$(document).on('click', '#speak .act.face', (eve) => {
|
||||
|
||||
});
|
||||
@ -580,61 +599,80 @@
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="create" class="white center act">
|
||||
<div id="contacts" class="hue2 page">
|
||||
<style>
|
||||
#create {
|
||||
position: fixed;
|
||||
bottom: 2em;
|
||||
right: 2em;
|
||||
font-size: 1em;
|
||||
font-family: Tahoma, arial;
|
||||
border-radius: 1em;
|
||||
z-index: 99999;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
opacity: 0.8;
|
||||
#contacts ul .face {
|
||||
float: left;
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
height: 2.5em;
|
||||
margin-right: 5%;
|
||||
}
|
||||
#contacts ul, #contacts li {
|
||||
overflow: visible;
|
||||
transition: all 0.2s ease-in;
|
||||
}
|
||||
#create:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
#create span {
|
||||
line-height: 2em;
|
||||
}
|
||||
#create .menu {
|
||||
display: none;
|
||||
height: 10em;
|
||||
width: 10em;
|
||||
bottom: 0em;
|
||||
right: 0em;
|
||||
overflow: visible;
|
||||
position: absolute;
|
||||
border-bottom-right-radius: 1em;
|
||||
#contacts .who {
|
||||
display: inline-block;
|
||||
margin-right: 2%;
|
||||
min-width: 250px;
|
||||
width: 15em;
|
||||
text-align: left;
|
||||
padding: 2%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#create:hover .menu {
|
||||
display: block;
|
||||
#contacts .what {
|
||||
}
|
||||
#create li {
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
#create a {
|
||||
color: black;
|
||||
}
|
||||
#create a:hover {
|
||||
color: #4D79D8;
|
||||
#contacts .spoke {
|
||||
}
|
||||
</style>
|
||||
<span class="huet act">+</span>
|
||||
<div class="white sap menu" style="width: 7em;">
|
||||
<ul class="left blackt gap">
|
||||
<a href="#out" class="act"><li>Sign Out</li></a>
|
||||
<a href="#settings" class="act"><li>Settings</li></a>
|
||||
<li>Profile</li>
|
||||
<li>Help</li>
|
||||
</ul>
|
||||
<p class="pad">Contacts</p>
|
||||
<ul class="mid row col center">
|
||||
</ul>
|
||||
<div class="model">
|
||||
<li class="who tint sap gully">
|
||||
<div class="gap">
|
||||
<span class="sort none"></span>
|
||||
<img class="face act none" crossOrigin="Anonymous">
|
||||
<big class="name"></big><br/>
|
||||
<i class="alias"></i><br/>
|
||||
<small>FB ID:</small> <span class="fbid"></span>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
<div style="height: 10%;"></div>
|
||||
<script>
|
||||
$.as.route.page('contacts', () => {
|
||||
if(!S.user.is){ return $.as.route('sign') }
|
||||
//S.gun.get('@').time(async (data, key, time) => {
|
||||
|
||||
// TODO: BUG!! switch from `on` to `once` to get Martti's {_} empty object bug.
|
||||
var $ul = $('#contacts ul');
|
||||
S.user.get('old').get('fb').map().on(async function(data){
|
||||
console.log('contact:', data);
|
||||
var key = data.fbid, tmp;
|
||||
if(!key){ return }
|
||||
var $li = $($('#fbid'+key)[0] || $('#contacts .model .who').clone(true,true).attr('id', 'fbid'+key)[(tmp = $.as.sort(data.name||1, $ul.children('li').first()))[0]?'insertBefore':'appendTo'](tmp[0] || $ul));
|
||||
|
||||
$li.find('.name').text(data.name);
|
||||
$li.find('.alias').text(data.alias);
|
||||
$li.find('.fbid').text(data.fbid);
|
||||
tmp = $li.find('img').attr('src', data.face || data.tmp);
|
||||
if(!data.face){
|
||||
var ref = this;
|
||||
$.fn.upload.shrink(data.tmp, function(b64){
|
||||
ref.get('face').put(b64);
|
||||
}, 100);
|
||||
}
|
||||
$('html, body').stop(true, true).animate({scrollTop: $ul.height()});
|
||||
});
|
||||
function img2b64(img, cb){
|
||||
var c = document.createElement('canvas');
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.drawImage(img, 10, 10);
|
||||
cb(c.toDataURL());
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="tell" class="center">
|
||||
@ -666,28 +704,9 @@
|
||||
</style>
|
||||
<p class="mid black">Hello world!</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.joy {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
background: url(./pop.png) no-repeat;
|
||||
background-position: -2800px 0;
|
||||
pointer-events: none;
|
||||
animation: joy 1s steps(28);
|
||||
}
|
||||
@keyframes joy {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -2800px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- textarea id='debug' class="no-ne" style="position: fixed; bottom: 0; left: 0; width: 25%; height: 30%"></textarea -->
|
||||
|
||||
<script>
|
||||
|
||||
$.as.route.page('person', () => {
|
||||
if(!user.is){ return $.as.route('hi') }
|
||||
var pub = location.hash.split('/').slice(-1)[0];
|
||||
@ -696,7 +715,6 @@
|
||||
});
|
||||
|
||||
$(document).upload(function resize(e, up){
|
||||
console.log("WOAH");
|
||||
if(e.err){ return }
|
||||
var m = $($("#d"+e.id)[0] || $('#d0').clone(true,true).attr('id', 'd'+e.id).css('backgroundImage', '').appendTo('#draft')).addClass('pulse');
|
||||
if(up){ return up.shrink(e, resize, 1000) }
|
||||
@ -708,17 +726,10 @@
|
||||
backgroundSize: 'cover'
|
||||
});
|
||||
});
|
||||
|
||||
window.fun = function fun(e){ setTimeout(() => {
|
||||
e = e || {}; var $img = $('<div class="joy"></div>')
|
||||
.css({position: 'fixed', width: 100,
|
||||
top: (e.y || e.clientY || (Math.random() * $(window).height()))-50,
|
||||
left: (e.x || e.clientX || e.pageX || (Math.random() * $(window).width()))-50,
|
||||
transform: 'rotate('+(Math.random() * 360)+'deg)'
|
||||
}).appendTo('body');
|
||||
setTimeout(() => { $img.remove() },800);
|
||||
},10)};
|
||||
$(document).on('keyup', fun).on('touchstart', fun).on('mousedown', fun);
|
||||
</script>
|
||||
<!-- script async src="../../gun/lib/fun.js"></script -->
|
||||
<script async src="../../gun/lib/normalize.js"></script>
|
||||
<script async src="../../gun/lib/monotype.js"></script>
|
||||
<script async src="../../gun/lib/meta.js"></script>
|
||||
</body>
|
||||
</html>
|
3
examples/react-native/.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["module:metro-react-native-babel-preset"]
|
||||
}
|
6
examples/react-native/.buckconfig
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
[android]
|
||||
target = Google Inc.:Google APIs:23
|
||||
|
||||
[maven_repositories]
|
||||
central = https://repo1.maven.org/maven2
|
70
examples/react-native/.flowconfig
Normal file
@ -0,0 +1,70 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow/
|
||||
node_modules/react-native/flow-github/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# get basename
|
||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
|
||||
# strip .js or .js.flow suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
|
||||
# strip .ios suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
|
||||
module.system.haste.paths.blacklist=.*/__tests__/.*
|
||||
module.system.haste.paths.blacklist=.*/__mocks__/.*
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[version]
|
||||
^0.78.0
|
1
examples/react-native/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.pbxproj -text
|
56
examples/react-native/.gitignore
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://docs.fastlane.tools/best-practices/source-control/
|
||||
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
1
examples/react-native/.watchmanconfig
Normal file
@ -0,0 +1 @@
|
||||
{}
|
18
examples/react-native/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Gun on react-native!
|
||||
---
|
||||
### running the demo
|
||||
1. do `yarn install` on the directory of the demo `examples/react-native`
|
||||
2. run the demo with `react-native run-ios` or `react-native run-android`
|
||||
|
||||
### debugging
|
||||
i would recommend using [react-native-debugger](https://github.com/facebook/react-devtools/tree/master/packages/react-devtools) but you can use chrome's debugger as well
|
||||
|
||||
- ios: `cmd+D` then `Debug JS Remotely`
|
||||
- android: `cmd+M` then `Debug JS Remotely`
|
||||
|
||||
now you have access to the gun globals on the console which are
|
||||
`gun` -> the root gun
|
||||
`user` -> the gun user
|
||||
---
|
||||
# how it all of this is done
|
||||
since react-native doesnt provide the crypto module that we desire the most and all of the packages are incompatible with react-native/sea, and so to get `sea.js` working we use a webview(react-native browser) and bridge the crypto module from that browser to the global `window` and thats exactly what `webview-crypto` does, thanks to [webview-crypto repo](https://github.com/saulshanabrook/webview-crypto), the webview-crypto provided in this repo is somewhat the same but modified to get it working and mostly compatible with sea/react-native (even though there is a polyfiller for that but it just doesnt work ;/).
|
65
examples/react-native/android/app/BUCK
Normal file
@ -0,0 +1,65 @@
|
||||
# To learn about Buck see [Docs](https://buckbuild.com/).
|
||||
# To run your application with Buck:
|
||||
# - install Buck
|
||||
# - `npm start` - to start the packager
|
||||
# - `cd android`
|
||||
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
|
||||
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
|
||||
# - `buck install -r android/app` - compile, install and run application
|
||||
#
|
||||
|
||||
lib_deps = []
|
||||
|
||||
for jarfile in glob(['libs/*.jar']):
|
||||
name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
|
||||
lib_deps.append(':' + name)
|
||||
prebuilt_jar(
|
||||
name = name,
|
||||
binary_jar = jarfile,
|
||||
)
|
||||
|
||||
for aarfile in glob(['libs/*.aar']):
|
||||
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
|
||||
lib_deps.append(':' + name)
|
||||
android_prebuilt_aar(
|
||||
name = name,
|
||||
aar = aarfile,
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = "all-libs",
|
||||
exported_deps = lib_deps,
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = "app-code",
|
||||
srcs = glob([
|
||||
"src/main/java/**/*.java",
|
||||
]),
|
||||
deps = [
|
||||
":all-libs",
|
||||
":build_config",
|
||||
":res",
|
||||
],
|
||||
)
|
||||
|
||||
android_build_config(
|
||||
name = "build_config",
|
||||
package = "com.gundemo",
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = "res",
|
||||
package = "com.gundemo",
|
||||
res = "src/main/res",
|
||||
)
|
||||
|
||||
android_binary(
|
||||
name = "app",
|
||||
keystore = "//android/keystores:debug",
|
||||
manifest = "src/main/AndroidManifest.xml",
|
||||
package_type = "debug",
|
||||
deps = [
|
||||
":app-code",
|
||||
],
|
||||
)
|
151
examples/react-native/android/app/build.gradle
Normal file
@ -0,0 +1,151 @@
|
||||
apply plugin: "com.android.application"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
* and bundleReleaseJsAndAssets).
|
||||
* These basically call `react-native bundle` with the correct arguments during the Android build
|
||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
|
||||
* bundle directly from the development server. Below you can see all the possible configurations
|
||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the
|
||||
* `apply from: "../../node_modules/react-native/react.gradle"` line.
|
||||
*
|
||||
* project.ext.react = [
|
||||
* // the name of the generated asset file containing your JS bundle
|
||||
* bundleAssetName: "index.android.bundle",
|
||||
*
|
||||
* // the entry file for bundle generation
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
* bundleInDebug: false,
|
||||
*
|
||||
* // whether to bundle JS and assets in release mode
|
||||
* bundleInRelease: true,
|
||||
*
|
||||
* // whether to bundle JS and assets in another build variant (if configured).
|
||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'bundleIn${productFlavor}${buildType}'
|
||||
* // 'bundleIn${buildType}'
|
||||
* // bundleInFreeDebug: true,
|
||||
* // bundleInPaidRelease: true,
|
||||
* // bundleInBeta: true,
|
||||
*
|
||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
||||
* // for example: to disable dev mode in the staging build type (if configured)
|
||||
* devDisabledInStaging: true,
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
||||
* // 'devDisabledIn${buildType}'
|
||||
*
|
||||
* // the root of your project, i.e. where "package.json" lives
|
||||
* root: "../../",
|
||||
*
|
||||
* // where to put the JS bundle asset in debug mode
|
||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
|
||||
*
|
||||
* // where to put the JS bundle asset in release mode
|
||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in debug mode
|
||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in release mode
|
||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
|
||||
*
|
||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
|
||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
|
||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
|
||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
|
||||
* // for example, you might want to remove it from here.
|
||||
* inputExcludes: ["android/**", "ios/**"],
|
||||
*
|
||||
* // override which node gets called and with what additional arguments
|
||||
* nodeExecutableAndArgs: ["node"],
|
||||
*
|
||||
* // supply additional arguments to the packager
|
||||
* extraPackagerArgs: []
|
||||
* ]
|
||||
*/
|
||||
|
||||
project.ext.react = [
|
||||
entryFile: "index.js"
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native/react.gradle"
|
||||
|
||||
/**
|
||||
* Set this to true to create two separate APKs instead of one:
|
||||
* - An APK that only works on ARM devices
|
||||
* - An APK that only works on x86 devices
|
||||
* The advantage is the size of the APK is reduced by about 4MB.
|
||||
* Upload all the APKs to the Play Store and people will download
|
||||
* the correct one based on the CPU architecture of their device.
|
||||
*/
|
||||
def enableSeparateBuildPerCPUArchitecture = false
|
||||
|
||||
/**
|
||||
* Run Proguard to shrink the Java bytecode in release builds.
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = false
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.gundemo"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
|
||||
def versionCodes = ["armeabi-v7a":1, "x86":2]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-webview-bridge')
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
}
|
17
examples/react-native/android/app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@ -0,0 +1,26 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.gundemo">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="false"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,15 @@
|
||||
package com.gundemo;
|
||||
|
||||
import com.facebook.react.ReactActivity;
|
||||
|
||||
public class MainActivity extends ReactActivity {
|
||||
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript.
|
||||
* This is used to schedule rendering of the component.
|
||||
*/
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
return "GunDemo";
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.gundemo;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new WebViewBridgePackage()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">GunDemo</string>
|
||||
</resources>
|
@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
39
examples/react-native/android/build.gradle
Normal file
@ -0,0 +1,39 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "27.0.3"
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 27
|
||||
targetSdkVersion = 26
|
||||
supportLibVersion = "27.1.1"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
google()
|
||||
jcenter()
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url "$rootDir/../node_modules/react-native/android"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '4.4'
|
||||
distributionUrl = distributionUrl.replace("bin", "all")
|
||||
}
|
18
examples/react-native/android/gradle.properties
Normal file
@ -0,0 +1,18 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
BIN
examples/react-native/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
5
examples/react-native/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
172
examples/react-native/android/gradlew
vendored
Executable file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
84
examples/react-native/android/gradlew.bat
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
8
examples/react-native/android/keystores/BUCK
Normal file
@ -0,0 +1,8 @@
|
||||
keystore(
|
||||
name = "debug",
|
||||
properties = "debug.keystore.properties",
|
||||
store = "debug.keystore",
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
)
|
@ -0,0 +1,4 @@
|
||||
key.store=debug.keystore
|
||||
key.alias=androiddebugkey
|
||||
key.store.password=android
|
||||
key.alias.password=android
|
5
examples/react-native/android/settings.gradle
Normal file
@ -0,0 +1,5 @@
|
||||
rootProject.name = 'GunDemo'
|
||||
include ':react-native-webview-bridge'
|
||||
project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
|
||||
|
||||
include ':app'
|
4
examples/react-native/app.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "GunDemo",
|
||||
"displayName": "GunDemo"
|
||||
}
|
8
examples/react-native/index.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/** @format */
|
||||
import './shim';
|
||||
import {AppRegistry} from 'react-native';
|
||||
import App from './src/App';
|
||||
import {name as appName} from './app.json';
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
console.disableYellowBox = true;
|
54
examples/react-native/ios/GunDemo-tvOS/Info.plist
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
24
examples/react-native/ios/GunDemo-tvOSTests/Info.plist
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
1590
examples/react-native/ios/GunDemo.xcodeproj/project.pbxproj
Normal file
14
examples/react-native/ios/GunDemo/AppDelegate.h
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@end
|
35
examples/react-native/ios/GunDemo/AppDelegate.m
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
NSURL *jsCodeLocation;
|
||||
|
||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||
moduleName:@"GunDemo"
|
||||
initialProperties:nil
|
||||
launchOptions:launchOptions];
|
||||
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [UIViewController new];
|
||||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="GunDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
60
examples/react-native/ios/GunDemo/Info.plist
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>GunDemo</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
16
examples/react-native/ios/GunDemo/main.m
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
68
examples/react-native/ios/GunDemoTests/GunDemoTests.m
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#define TIMEOUT_SECONDS 600
|
||||
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
|
||||
|
||||
@interface GunDemoTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation GunDemoTests
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
if (test(view)) {
|
||||
return YES;
|
||||
}
|
||||
for (UIView *subview in [view subviews]) {
|
||||
if ([self findSubviewInView:subview matching:test]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)testRendersWelcomeScreen
|
||||
{
|
||||
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
BOOL foundElement = NO;
|
||||
|
||||
__block NSString *redboxError = nil;
|
||||
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
|
||||
if (level >= RCTLogLevelError) {
|
||||
redboxError = message;
|
||||
}
|
||||
});
|
||||
|
||||
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
|
||||
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
RCTSetLogFunction(RCTDefaultLogFunction);
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@end
|
24
examples/react-native/ios/GunDemoTests/Info.plist
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
30
examples/react-native/package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "GunDemo",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": "^5.2.1",
|
||||
"encode-utf8": "^1.0.2",
|
||||
"fast-base64-encode": "^1.0.0",
|
||||
"gun": "^0.9.99999",
|
||||
"lodash": "^4.17.11",
|
||||
"react": "16.6.1",
|
||||
"react-native": "0.57.5",
|
||||
"react-native-webview-bridge": "^0.40.1",
|
||||
"serialize-error": "^3.0.0",
|
||||
"text-encoding": "^0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "23.6.0",
|
||||
"jest": "23.6.0",
|
||||
"metro-react-native-babel-preset": "0.49.2",
|
||||
"react-test-renderer": "16.6.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native"
|
||||
}
|
||||
}
|
20
examples/react-native/shim.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
if (typeof __dirname === 'undefined') global.__dirname = '/'
|
||||
if (typeof __filename === 'undefined') global.__filename = ''
|
||||
|
||||
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer
|
||||
|
||||
const isDev = typeof __DEV__ === 'boolean' && __DEV__
|
||||
process.env['NODE_ENV'] = isDev ? 'development' : 'production'
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.debug = isDev ? '*' : ''
|
||||
}
|
||||
|
||||
global.location = {
|
||||
protocol: 'file:',
|
||||
host: '',
|
||||
};
|
||||
|
||||
const { TextEncoder, TextDecoder } = require('text-encoding');
|
||||
|
||||
global.TextDecoder = TextDecoder;
|
||||
global.TextEncoder = TextEncoder;
|
152
examples/react-native/src/App/Demo.js
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
import * as React from 'react';
|
||||
import {View, StyleSheet, TextInput, Text, TouchableOpacity, AsyncStorage} from 'react-native';
|
||||
|
||||
import Gun from 'gun/gun';
|
||||
import 'gun/lib/open';
|
||||
import '../extensions/sea';
|
||||
|
||||
import adapter from '../extensions/asyncStorageAdapter';
|
||||
|
||||
Gun.on('create', function(db) {
|
||||
this.to.next(db);
|
||||
const pluginInterop = function(middleware) {
|
||||
return function(request) {
|
||||
this.to.next(request);
|
||||
return middleware(request, db);
|
||||
};
|
||||
}
|
||||
|
||||
// Register the adapter
|
||||
db.on('get', pluginInterop(adapter.read));
|
||||
db.on('put', pluginInterop(adapter.write));
|
||||
});
|
||||
|
||||
export class Demo extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.gun = new Gun();
|
||||
this.user = this.gun.user();
|
||||
|
||||
window.gun = this.gun;
|
||||
window.user = this.user;
|
||||
|
||||
this.state = {
|
||||
authenticated: false,
|
||||
list: [],
|
||||
listText: '',
|
||||
username: '',
|
||||
password: '',
|
||||
}
|
||||
}
|
||||
|
||||
hookUserList = () => {
|
||||
this.user.get('list').open((list) => {
|
||||
const userList = Object.keys(list).reduce((newList, key) => {
|
||||
if (!!Object.keys(list[key]).length) {
|
||||
return [...newList, {text: list[key].text, key}];
|
||||
};
|
||||
}, []);
|
||||
this.setState({
|
||||
list: userList || [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addToList = () => {
|
||||
this.user.get('list').set({text: this.state.listText});
|
||||
}
|
||||
|
||||
doSignin = () => {
|
||||
this.user.auth(this.state.username, this.state.password, (d) => {
|
||||
if (d.err) {
|
||||
console.log('err', d.err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({authenticated: true});
|
||||
this.hookUserList();
|
||||
});
|
||||
}
|
||||
|
||||
doSignup = () => {
|
||||
this.user.create(this.state.username, this.state.password, () => {
|
||||
this.doSignin();
|
||||
});
|
||||
}
|
||||
|
||||
loginScreen = () => {
|
||||
return (
|
||||
<View style={styles.sub}>
|
||||
<TextInput placeholder="username" onChangeText={(username) => this.setState({username})} value={this.state.username} style={styles.input} />
|
||||
<TextInput placeholder="password" secureTextEntry={true} onChangeText={(password) => this.setState({password})} value={this.state.password} style={styles.input} />
|
||||
<TouchableOpacity onPress={this.doSignin} style={styles.button}>
|
||||
<Text>Sign in</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={this.doSignup} style={styles.button}>
|
||||
<Text>Sign up</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
userListScreen = () => {
|
||||
return (
|
||||
<View style={styles.sub}>
|
||||
{
|
||||
!!this.state.list.length && this.state.list.map((item) => <Text key={item.key}>* {item.text}</Text>)
|
||||
}
|
||||
|
||||
<TextInput placeholder="text here" onChangeText={(listText) => this.setState({listText})} value={this.state.listText} style={styles.input} />
|
||||
<TouchableOpacity onPress={this.addToList} style={styles.button}>
|
||||
<Text>Add to list</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{
|
||||
this.state.authenticated ?
|
||||
this.userListScreen() : this.loginScreen()
|
||||
}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
sub: {
|
||||
height: '50%',
|
||||
width: '60%',
|
||||
justifyContent: 'space-between',
|
||||
padding: 4,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: 50,
|
||||
},
|
||||
input: {
|
||||
borderColor: 'black',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
width: '100%',
|
||||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: '32%',
|
||||
},
|
||||
});
|
92
examples/react-native/src/App/PolyFillCrypto.js
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import * as React from 'react';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
|
||||
import WebViewBridge from 'react-native-webview-bridge';
|
||||
|
||||
import { MainWorker, webViewWorkerString } from '../webview-crypto';
|
||||
|
||||
import encodeUtf8 from 'encode-utf8';
|
||||
import encodeBase64 from 'fast-base64-encode';
|
||||
|
||||
const base64EncodeString = (input) => {
|
||||
return encodeBase64(new Uint8Array(encodeUtf8(input)));
|
||||
};
|
||||
|
||||
const internalLibIOS = `
|
||||
${webViewWorkerString}
|
||||
(function () {
|
||||
var wvw = new WebViewWorker(WebViewBridge.send.bind(WebViewBridge));
|
||||
WebViewBridge.onMessage = wvw.onMainMessage.bind(wvw);
|
||||
}());
|
||||
`;
|
||||
|
||||
const intermediateLib = `
|
||||
${webViewWorkerString}
|
||||
(function () {
|
||||
var wvw = new WebViewWorker(WebViewBridge.send.bind(WebViewBridge));
|
||||
WebViewBridge.onMessage = wvw.onMainMessage.bind(wvw);
|
||||
}());
|
||||
`;
|
||||
|
||||
const internalLibAndroid = `eval(window.atob('${base64EncodeString(intermediateLib)}'))`;
|
||||
|
||||
export default class PolyfillCrypto extends React.Component {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
let worker;
|
||||
const uri = 'file:///android_asset/html/blank.html';
|
||||
return (
|
||||
<View style={styles.hidden}>
|
||||
<WebViewBridge
|
||||
ref={(c) => {
|
||||
if (c && !worker) {
|
||||
worker = new MainWorker(c.sendToBridge, this.props.debug);
|
||||
|
||||
if (window.crypto) {
|
||||
// we are in chrome debugger
|
||||
// this means overridng the crypto object itself won't
|
||||
// work, so we have to override all of it's methods
|
||||
for (const name in worker.crypto.subtle) {
|
||||
window.crypto.subtle[name] = worker.crypto.subtle[name];
|
||||
}
|
||||
window.crypto.fake = true;
|
||||
} else {
|
||||
window.crypto = worker.crypto;
|
||||
}
|
||||
window.crypto.loaded = true;
|
||||
console.log('*** poly injected', window.crypto);
|
||||
}
|
||||
}}
|
||||
onBridgeMessage={
|
||||
// can't refer to this.state.onBridgeMessage directly
|
||||
// because it is not defined when this component is first
|
||||
// started, only set in `ref`
|
||||
(message) => {
|
||||
worker.onWebViewMessage(message);
|
||||
}
|
||||
}
|
||||
injectedJavaScript={
|
||||
Platform.OS === 'android' ? internalLibAndroid : internalLibIOS
|
||||
}
|
||||
onError={(error) => {
|
||||
console.warn('Error creating webview: ', error);
|
||||
}}
|
||||
javaScriptEnabled={true}
|
||||
source={{
|
||||
uri: Platform.OS === 'android' ? uri : 'about:blank',
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
hidden: {
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
});
|
26
examples/react-native/src/App/app.js
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Sample React Native App
|
||||
* https://github.com/facebook/react-native
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import {Demo} from './Demo';
|
||||
|
||||
import PolyFillCrypto from './PolyFillCrypto';
|
||||
|
||||
|
||||
export class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<PolyFillCrypto />
|
||||
<Demo/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
1
examples/react-native/src/App/index.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {App as default} from './app';
|
75
examples/react-native/src/extensions/asyncStorageAdapter.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
import * as Gun from 'gun';
|
||||
import { AsyncStorage } from 'react-native';
|
||||
|
||||
const readNode = (key, cb) => {
|
||||
AsyncStorage.getItem(key || '', cb);
|
||||
};
|
||||
|
||||
const read = (request, db) => {
|
||||
const { get } = request;
|
||||
|
||||
const dedupid = request['#'];
|
||||
const key = get['#'];
|
||||
const field = get['.'];
|
||||
|
||||
const done = (err, data) => {
|
||||
if (!data && !err) {
|
||||
db.on('in', {
|
||||
'@': dedupid,
|
||||
put: null,
|
||||
err: null,
|
||||
});
|
||||
} else {
|
||||
db.on('in', {
|
||||
'@': dedupid,
|
||||
put: Gun.graph.node(data),
|
||||
err,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const acknowledgeRet = (err, result) => {
|
||||
if (err) {
|
||||
done(err);
|
||||
} else if (result === null) {
|
||||
// Nothing found
|
||||
done(null);
|
||||
} else {
|
||||
const temp = JSON.parse(result);
|
||||
if (field) {
|
||||
done(null, temp[field] || null);
|
||||
} else {
|
||||
done(null, temp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
readNode(key || '', acknowledgeRet);
|
||||
};
|
||||
|
||||
const write = (request, db) => {
|
||||
const { put: graph } = request;
|
||||
const keys = Object.keys(graph);
|
||||
const dedupid = graph['#'];
|
||||
|
||||
const instructions = keys.map((key) => {
|
||||
return [key, JSON.stringify(graph[key] || {})];
|
||||
});
|
||||
|
||||
AsyncStorage.multiMerge(instructions, (err) => {
|
||||
db.on('in', {
|
||||
'#': dedupid,
|
||||
ok: !err || err.length === 0,
|
||||
err,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// This returns a promise, it can be awaited!
|
||||
const reset = () => AsyncStorage.clear();
|
||||
|
||||
export default {
|
||||
read,
|
||||
write,
|
||||
reset,
|
||||
};
|
1215
examples/react-native/src/extensions/sea.js
vendored
Normal file
14
examples/react-native/src/webview-crypto/MainWorker.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
export default class MainWorker {
|
||||
private sendToWebView;
|
||||
private debug;
|
||||
readonly crypto: Crypto;
|
||||
private readonly subtle;
|
||||
private static uuid;
|
||||
private toSend;
|
||||
private readyToSend;
|
||||
private messages;
|
||||
constructor(sendToWebView: (message: string) => void, debug?: boolean);
|
||||
onWebViewMessage(message: string): void;
|
||||
private getRandomValues;
|
||||
private callMethod;
|
||||
}
|
170
examples/react-native/src/webview-crypto/MainWorker.js
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
import serializeError from 'serialize-error';
|
||||
import { parse, stringify } from './serializeBinary';
|
||||
const SUBTLE_METHODS = [
|
||||
'encrypt',
|
||||
'decrypt',
|
||||
'sign',
|
||||
'verify',
|
||||
'digest',
|
||||
'generateKey',
|
||||
'deriveKey',
|
||||
'deriveBits',
|
||||
'importKey',
|
||||
'exportKey',
|
||||
'wrapKey',
|
||||
'unwrapKey',
|
||||
];
|
||||
/*
|
||||
MainWorker provides a `crypto` attribute that proxies method calls
|
||||
to the webview.
|
||||
|
||||
It sends strings to the webview in the format:
|
||||
|
||||
{
|
||||
id: <id>,
|
||||
method: getRandomValues | subtle.<method name>,
|
||||
args: [<serialized arg>]
|
||||
}
|
||||
|
||||
When the webview succeeds in completeing that method, it gets backs:
|
||||
|
||||
{
|
||||
id: <id>,
|
||||
value: <serialized return value>
|
||||
}
|
||||
|
||||
And when it fails:
|
||||
|
||||
{
|
||||
id: <id>,
|
||||
reason: <serialized rejected reason>,
|
||||
}
|
||||
|
||||
*/
|
||||
export default class MainWorker {
|
||||
// sendToWebView should take a string and send that message to the webview
|
||||
constructor(sendToWebView, debug = false) {
|
||||
this.sendToWebView = sendToWebView;
|
||||
this.debug = debug;
|
||||
// hold a queue of messages to send, in case someone calls crypto
|
||||
// before the webview is initialized
|
||||
this.toSend = [];
|
||||
this.readyToSend = false;
|
||||
// Holds the `resolve` and `reject` function for all the promises
|
||||
// we are working on
|
||||
this.messages = {};
|
||||
}
|
||||
get crypto() {
|
||||
const callMethod = this.callMethod;
|
||||
return {
|
||||
subtle: this.subtle,
|
||||
getRandomValues: this.getRandomValues.bind(this),
|
||||
fake: true,
|
||||
};
|
||||
}
|
||||
get subtle() {
|
||||
const s = {};
|
||||
for (const m of SUBTLE_METHODS) {
|
||||
s[m] = (...args) => {
|
||||
return this.callMethod(`subtle.${m}`, args, true);
|
||||
};
|
||||
}
|
||||
return s;
|
||||
}
|
||||
// http://stackoverflow.com/a/105074/907060
|
||||
static uuid() {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return `${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}`;
|
||||
}
|
||||
onWebViewMessage(message) {
|
||||
// first message just tells us the webview is ready
|
||||
if (!this.readyToSend) {
|
||||
if (this.debug) {
|
||||
console.log('[webview-crypto] Got first message; ready to send');
|
||||
}
|
||||
this.readyToSend = true;
|
||||
for (const m of this.toSend) {
|
||||
this.sendToWebView(m);
|
||||
}
|
||||
return;
|
||||
}
|
||||
parse(message)
|
||||
.then(({ id, value, reason }) => {
|
||||
if (this.debug) {
|
||||
console.log('[webview-crypto] Received message:', JSON.stringify({
|
||||
id,
|
||||
value,
|
||||
reason,
|
||||
}));
|
||||
}
|
||||
if (!id) {
|
||||
console.warn('[webview-crypto] no ID passed back from message:', JSON.stringify(serializeError(reason)));
|
||||
return;
|
||||
}
|
||||
const { resolve, reject } = this.messages[id];
|
||||
if (value) {
|
||||
resolve(value);
|
||||
}
|
||||
else {
|
||||
reject(reason);
|
||||
}
|
||||
delete this.messages[id];
|
||||
})
|
||||
.catch((reason) => {
|
||||
console.warn('[webview-crypto] error in `parse` of message:', JSON.stringify(message), 'reason:', JSON.stringify(serializeError(reason)));
|
||||
});
|
||||
}
|
||||
getRandomValues(array) {
|
||||
const promise = this.callMethod('getRandomValues', [array], false);
|
||||
// make the _promise not enumerable so it isn't JSON stringified,
|
||||
// which could lead to an infinite loop with Angular's zone promises
|
||||
Object.defineProperty(array, '_promise', {
|
||||
value: promise,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
});
|
||||
promise.then((updatedArray) => {
|
||||
array.set(updatedArray);
|
||||
});
|
||||
return array;
|
||||
}
|
||||
callMethod(method, args, waitForArrayBufferView) {
|
||||
const id = MainWorker.uuid();
|
||||
// store this promise, so we can resolve it when we get a message
|
||||
// back from the web view
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.messages[id] = { resolve, reject };
|
||||
});
|
||||
const payloadObject = { method, id, args };
|
||||
if (this.debug) {
|
||||
console.log('[webview-crypto] Sending message:', JSON.stringify({
|
||||
method,
|
||||
args,
|
||||
payloadObject,
|
||||
}));
|
||||
}
|
||||
stringify(payloadObject, waitForArrayBufferView)
|
||||
.then((message) => {
|
||||
if (this.readyToSend) {
|
||||
this.sendToWebView(message);
|
||||
}
|
||||
else {
|
||||
this.toSend.push(message);
|
||||
}
|
||||
})
|
||||
.catch((reason) => {
|
||||
this.messages[id].reject({
|
||||
message: `exception in stringify-ing message: ${method} ${id}`,
|
||||
reason,
|
||||
});
|
||||
delete this.messages[id];
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=MainWorker.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"MainWorker.js","sourceRoot":"","sources":["../src/MainWorker.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAA+B,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAElF,MAAM,cAAc,GAAG;IACtB,SAAS;IACT,SAAS;IACT,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,aAAa;IACb,WAAW;IACX,YAAY;IACZ,WAAW;IACX,WAAW;IACX,SAAS;IACT,WAAW;CACX,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BE;AACF,MAAM,CAAC,OAAO,OAAO,UAAU;IA2C9B,0EAA0E;IAC1E,YAAoB,aAAwC,EAAU,QAAQ,KAAK;QAA/D,kBAAa,GAAb,aAAa,CAA2B;QAAU,UAAK,GAAL,KAAK,CAAQ;QAfnF,iEAAiE;QACjE,oCAAoC;QAC5B,WAAM,GAAa,EAAE,CAAC;QACtB,gBAAW,GAAG,KAAK,CAAC;QAE5B,iEAAiE;QACjE,oBAAoB;QACZ,aAAQ,GAKZ,EAAE,CAAC;IAG+E,CAAC;IA3CvF,IAAI,MAAM;QACT,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,OAAO;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAChD,IAAI,EAAE,IAAI;SACH,CAAC;IACV,CAAC;IAED,IAAY,MAAM;QACjB,MAAM,CAAC,GAAQ,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE;YAC/B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAW,EAAE,EAAE;gBACzB,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACnD,CAAC,CAAC;SACF;QACD,OAAO,CAAiB,CAAC;IAC1B,CAAC;IAED,2CAA2C;IACnC,MAAM,CAAC,IAAI;QAClB,SAAS,EAAE;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC;iBAC9C,QAAQ,CAAC,EAAE,CAAC;iBACZ,SAAS,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC1E,CAAC;IAkBD,gBAAgB,CAAC,OAAe;QAC/B,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YACtB,IAAI,IAAI,CAAC,KAAK,EAAE;gBACf,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;aACjE;YACD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE;gBAC5B,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aACtB;YACD,OAAO;SACP;QACD,KAAK,CAAC,OAAO,CAAC;aACZ,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/B,IAAI,IAAI,CAAC,KAAK,EAAE;gBACf,OAAO,CAAC,GAAG,CACV,oCAAoC,EACpC,IAAI,CAAC,SAAS,CAAC;oBACd,EAAE;oBACF,KAAK;oBACL,MAAM;iBACN,CAAC,CACF,CAAC;aACF;YACD,IAAI,CAAC,EAAE,EAAE;gBACR,OAAO,CAAC,IAAI,CACX,kDAAkD,EAClD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CACtC,CAAC;gBACF,OAAO;aACP;YACD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC9C,IAAI,KAAK,EAAE;gBACV,OAAO,CAAC,KAAK,CAAC,CAAC;aACf;iBAAM;gBACN,MAAM,CAAC,MAAM,CAAC,CAAC;aACf;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE;YACjB,OAAO,CAAC,IAAI,CACX,+CAA+C,EAC/C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EACvB,SAAS,EACT,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CACtC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,eAAe,CAAC,KAAkC;QACzD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QAEnE,iEAAiE;QACjE,oEAAoE;QACpE,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE;YACxC,KAAK,EAAE,OAAO;YACd,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,IAAI;SACd,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC,CAAC,YAA6B,EAAE,EAAE;YAC7C,KAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,UAAU,CAAC,MAAc,EAAE,IAAW,EAAE,sBAA+B;QAC9E,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;QAC7B,iEAAiE;QACjE,yBAAyB;QACzB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC/C,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,KAAK,EAAE;YACf,OAAO,CAAC,GAAG,CACV,mCAAmC,EACnC,IAAI,CAAC,SAAS,CAAC;gBACd,MAAM;gBACN,IAAI;gBACJ,aAAa;aACb,CAAC,CACF,CAAC;SACF;QACD,SAAS,CAAC,aAAa,EAAE,sBAAsB,CAAC;aAC9C,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YACjB,IAAI,IAAI,CAAC,WAAW,EAAE;gBACrB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;aAC5B;iBAAM;gBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aAC1B;QACF,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE;YACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;gBACxB,OAAO,EAAE,uCAAuC,MAAM,IAAI,EAAE,EAAE;gBAC9D,MAAM;aACN,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACJ,OAAO,OAAO,CAAC;IAChB,CAAC;CACD"}
|
6
examples/react-native/src/webview-crypto/WebViewWorker.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export declare class WebViewWorker {
|
||||
private sendToMain;
|
||||
constructor(sendToMain: (message: string) => void);
|
||||
onMainMessage(message: string): Promise<void>;
|
||||
send(data: any): Promise<void>;
|
||||
}
|
75
examples/react-native/src/webview-crypto/WebViewWorker.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import serializeError from 'serialize-error';
|
||||
import { subtle } from './compat';
|
||||
import { parse, stringify } from './serializeBinary';
|
||||
export class WebViewWorker {
|
||||
constructor(sendToMain) {
|
||||
this.sendToMain = sendToMain;
|
||||
sendToMain('We are ready!');
|
||||
}
|
||||
onMainMessage(message) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let id;
|
||||
let method;
|
||||
let args;
|
||||
try {
|
||||
({ id, method, args } = yield parse(message));
|
||||
}
|
||||
catch (e) {
|
||||
yield this.send({
|
||||
reason: `Couldn't parse data: ${e}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
let value;
|
||||
try {
|
||||
if (method === 'getRandomValues') {
|
||||
value = crypto.getRandomValues(args[0]);
|
||||
}
|
||||
else {
|
||||
const methodName = method.split('.')[1];
|
||||
console.log(methodName, args);
|
||||
value = yield subtle()[methodName].apply(subtle(), args);
|
||||
// if we import a crypto key, we want to save how we imported it
|
||||
// so we can send that back and re-create the key later
|
||||
if (methodName === 'importKey') {
|
||||
value._import = {
|
||||
format: args[0],
|
||||
keyData: args[1],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
yield this.send({ id, reason: serializeError(e) });
|
||||
return;
|
||||
}
|
||||
yield this.send({ id, value });
|
||||
});
|
||||
}
|
||||
send(data) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let message;
|
||||
try {
|
||||
message = yield stringify(data);
|
||||
}
|
||||
catch (e) {
|
||||
const newData = {
|
||||
id: data.id,
|
||||
reason: `stringify error ${e}`,
|
||||
};
|
||||
this.sendToMain(JSON.stringify(newData));
|
||||
return;
|
||||
}
|
||||
this.sendToMain(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=WebViewWorker.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"WebViewWorker.js","sourceRoot":"","sources":["../src/WebViewWorker.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,cAAc,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,OAAO,aAAa;IACzB,YAAoB,UAAqC;QAArC,eAAU,GAAV,UAAU,CAA2B;QACxD,UAAU,CAAC,eAAe,CAAC,CAAC;IAC7B,CAAC;IAEK,aAAa,CAAC,OAAe;;YAClC,IAAI,EAAU,CAAC;YACf,IAAI,MAAc,CAAC;YACnB,IAAI,IAAW,CAAC;YAChB,IAAI;gBACH,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;aAC9C;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,IAAI,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,wBAAwB,CAAC,EAAE;iBACnC,CAAC,CAAC;gBACH,OAAO;aACP;YACD,IAAI,KAAK,CAAC;YAEV,IAAI;gBACH,IAAI,MAAM,KAAK,iBAAiB,EAAE;oBACjC,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;iBACxC;qBAAM;oBACN,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBACxC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;oBAC9B,KAAK,GAAG,MAAO,MAAM,EAAU,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;oBAElE,gEAAgE;oBAChE,uDAAuD;oBACvD,IAAI,UAAU,KAAK,WAAW,EAAE;wBAC/B,KAAK,CAAC,OAAO,GAAG;4BACf,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;4BACf,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;yBAChB,CAAC;qBACF;iBACD;aACD;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAG,cAAsB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5D,OAAO;aACP;YACD,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChC,CAAC;KAAA;IAEK,IAAI,CAAC,IAAS;;YACnB,IAAI,OAAe,CAAC;YACpB,IAAI;gBACH,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,OAAO,GAAG;oBACf,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,MAAM,EAAE,mBAAmB,CAAC,EAAE;iBAC9B,CAAC;gBACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBACzC,OAAO;aACP;YACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;KAAA;CACD"}
|
8
examples/react-native/src/webview-crypto/asyncSerialize.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export interface ISerializer<T, S> {
|
||||
id: string;
|
||||
isType: (o: any) => boolean;
|
||||
toObject?: (t: T) => Promise<S>;
|
||||
fromObject?: (o: S) => Promise<T>;
|
||||
}
|
||||
export declare function toObjects(serializers: Array<ISerializer<any, any>>, o: any): Promise<any>;
|
||||
export declare function fromObjects(serializers: Array<ISerializer<any, any>>, o: any): Promise<any>;
|
56
examples/react-native/src/webview-crypto/asyncSerialize.js
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
// tslint:disable
|
||||
import find from 'lodash/find';
|
||||
class Serialized {
|
||||
}
|
||||
function isSerialized(object) {
|
||||
return object.hasOwnProperty('__serializer_id');
|
||||
}
|
||||
export function toObjects(serializers, o) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof o !== 'object') {
|
||||
return o;
|
||||
}
|
||||
const serializer = find(serializers, (s) => s.isType(o));
|
||||
if (serializer) {
|
||||
const value = serializer.toObject ? yield serializer.toObject(o) : o;
|
||||
return {
|
||||
__serializer_id: serializer.id,
|
||||
value: yield toObjects(serializers, value),
|
||||
};
|
||||
}
|
||||
const newO = o instanceof Array ? [] : {};
|
||||
for (const atr in o) {
|
||||
newO[atr] = yield toObjects(serializers, o[atr]);
|
||||
}
|
||||
return newO;
|
||||
});
|
||||
}
|
||||
export function fromObjects(serializers, o) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof o !== 'object') {
|
||||
return o;
|
||||
}
|
||||
if (isSerialized(o)) {
|
||||
const value = yield fromObjects(serializers, o.value);
|
||||
const serializer = find(serializers, ['id', o.__serializer_id]) || {};
|
||||
if (serializer.fromObject) {
|
||||
return serializer.fromObject(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
const newO = o instanceof Array ? [] : {};
|
||||
for (const atr in o) {
|
||||
newO[atr] = yield fromObjects(serializers, o[atr]);
|
||||
}
|
||||
return newO;
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=asyncSerialize.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"asyncSerialize.js","sourceRoot":"","sources":["../src/asyncSerialize.ts"],"names":[],"mappings":";;;;;;;;AAAA,iBAAiB;AACjB,OAAO,IAAI,MAAM,aAAa,CAAC;AAS/B,MAAM,UAAU;CAIf;AAED,SAAS,YAAY,CAAC,MAAW;IAChC,OAAO,MAAM,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAgB,SAAS,CAC9B,WAAyC,EACzC,CAAM;;QAEN,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YAC1B,OAAO,CAAC,CAAC;SACT;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,UAAU,EAAE;YACf,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrE,OAAO;gBACN,eAAe,EAAE,UAAU,CAAC,EAAE;gBAC9B,KAAK,EAAE,MAAM,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC;aAC5B,CAAC;SAChB;QAED,MAAM,IAAI,GAAQ,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;YACpB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACjD;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CAAA;AAED,MAAM,UAAgB,WAAW,CAChC,WAAyC,EACzC,CAAM;;QAEN,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YAC1B,OAAO,CAAC,CAAC;SACT;QAED,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE;YACpB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,EAAS,CAAC;YAC7E,IAAI,UAAU,CAAC,UAAU,EAAE;gBAC1B,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpC;YACD,OAAO,KAAK,CAAC;SACb;QAED,MAAM,IAAI,GAAQ,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;YACpB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACnD;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CAAA"}
|
1
examples/react-native/src/webview-crypto/compat.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare function subtle(): SubtleCrypto;
|
4
examples/react-native/src/webview-crypto/compat.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export function subtle() {
|
||||
return window.crypto.subtle || window.crypto.webkitSubtle;
|
||||
}
|
||||
//# sourceMappingURL=compat.js.map
|
1
examples/react-native/src/webview-crypto/compat.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../src/compat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;IACrB,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,IAAK,MAAM,CAAC,MAAc,CAAC,YAAY,CAAC;AACpE,CAAC"}
|
3
examples/react-native/src/webview-crypto/index.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import MainWorker from './MainWorker';
|
||||
import webViewWorkerString from './webViewWorkerString';
|
||||
export { MainWorker, webViewWorkerString };
|
4
examples/react-native/src/webview-crypto/index.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import MainWorker from './MainWorker';
|
||||
import webViewWorkerString from './webViewWorkerString';
|
||||
export { MainWorker, webViewWorkerString };
|
||||
//# sourceMappingURL=index.js.map
|
1
examples/react-native/src/webview-crypto/index.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC"}
|
5
examples/react-native/src/webview-crypto/serializeBinary.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export declare function parse(text: string): Promise<any>;
|
||||
export declare function stringify(value: any, waitForArrayBufferView?: boolean): Promise<string>;
|
||||
export interface IArrayBufferViewWithPromise extends ArrayBufferView {
|
||||
_promise?: Promise<ArrayBufferView>;
|
||||
}
|
160
examples/react-native/src/webview-crypto/serializeBinary.js
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import { fromObjects, toObjects } from './asyncSerialize';
|
||||
import { subtle } from './compat';
|
||||
export function parse(text) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// need decodeURIComponent so binary strings are transfered properly
|
||||
const deocodedText = unescape(text);
|
||||
const objects = JSON.parse(deocodedText);
|
||||
return fromObjects(serializers(true), objects);
|
||||
});
|
||||
}
|
||||
export function stringify(value, waitForArrayBufferView = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const serialized = yield toObjects(serializers(waitForArrayBufferView), value);
|
||||
// need encodeURIComponent so binary strings are transfered properly
|
||||
const message = JSON.stringify(serialized);
|
||||
return escape(message);
|
||||
});
|
||||
}
|
||||
function serializers(waitForArrayBufferView) {
|
||||
return [
|
||||
ArrayBufferSerializer,
|
||||
ArrayBufferViewSerializer(waitForArrayBufferView),
|
||||
CryptoKeySerializer,
|
||||
];
|
||||
}
|
||||
const ArrayBufferSerializer = {
|
||||
id: 'ArrayBuffer',
|
||||
isType: (o) => o instanceof ArrayBuffer,
|
||||
// from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
|
||||
// modified to use Int8Array so that we can hold odd number of bytes
|
||||
toObject: (ab) => __awaiter(this, void 0, void 0, function* () {
|
||||
return String.fromCharCode.apply(null, new Int8Array(ab));
|
||||
}),
|
||||
fromObject: (data) => __awaiter(this, void 0, void 0, function* () {
|
||||
const buf = new ArrayBuffer(data.length);
|
||||
const bufView = new Int8Array(buf);
|
||||
for (let i = 0, strLen = data.length; i < strLen; i++) {
|
||||
bufView[i] = data.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}),
|
||||
};
|
||||
function isArrayBufferViewWithPromise(obj) {
|
||||
return obj.hasOwnProperty('_promise');
|
||||
}
|
||||
// Normally we could just do `abv.constructor.name`, but in
|
||||
// JavaScriptCore, this wont work for some weird reason.
|
||||
// list from https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView
|
||||
function arrayBufferViewName(abv) {
|
||||
if (abv instanceof Int8Array) {
|
||||
return 'Int8Array';
|
||||
}
|
||||
if (abv instanceof Uint8Array) {
|
||||
return 'Uint8Array';
|
||||
}
|
||||
if (abv instanceof Uint8ClampedArray) {
|
||||
return 'Uint8ClampedArray';
|
||||
}
|
||||
if (abv instanceof Int16Array) {
|
||||
return 'Int16Array';
|
||||
}
|
||||
if (abv instanceof Uint16Array) {
|
||||
return 'Uint16Array';
|
||||
}
|
||||
if (abv instanceof Int32Array) {
|
||||
return 'Int32Array';
|
||||
}
|
||||
if (abv instanceof Uint32Array) {
|
||||
return 'Uint32Array';
|
||||
}
|
||||
if (abv instanceof Float32Array) {
|
||||
return 'Float32Array';
|
||||
}
|
||||
if (abv instanceof Float64Array) {
|
||||
return 'Float64Array';
|
||||
}
|
||||
if (abv instanceof DataView) {
|
||||
return 'DataView';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function ArrayBufferViewSerializer(waitForPromise) {
|
||||
return {
|
||||
id: 'ArrayBufferView',
|
||||
isType: ArrayBuffer.isView,
|
||||
toObject: (abv) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (waitForPromise) {
|
||||
// wait for promise to resolve if the abv was returned from getRandomValues
|
||||
if (isArrayBufferViewWithPromise(abv)) {
|
||||
yield abv._promise;
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: arrayBufferViewName(abv),
|
||||
buffer: abv.buffer,
|
||||
};
|
||||
}),
|
||||
fromObject: (abvs) => __awaiter(this, void 0, void 0, function* () {
|
||||
// tslint:disable-next-line
|
||||
return eval(`new ${abvs.name}(abvs.buffer)`);
|
||||
}),
|
||||
};
|
||||
}
|
||||
function hasData(ck) {
|
||||
return ck._import !== undefined;
|
||||
}
|
||||
const CryptoKeySerializer = {
|
||||
id: 'CryptoKey',
|
||||
isType: (o) => {
|
||||
const localStr = o.toLocaleString();
|
||||
// can't use CryptoKey or constructor on WebView iOS
|
||||
const isCryptoKey = localStr === '[object CryptoKey]' || localStr === '[object Key]';
|
||||
const isCryptoKeyWithData = o._import && !o.serialized;
|
||||
return isCryptoKey || isCryptoKeyWithData;
|
||||
},
|
||||
toObject: (ck) => __awaiter(this, void 0, void 0, function* () {
|
||||
// if we already have the import serialized, just return that
|
||||
if (hasData(ck)) {
|
||||
return {
|
||||
serialized: true,
|
||||
_import: ck._import,
|
||||
type: ck.type,
|
||||
extractable: ck.extractable,
|
||||
algorithm: ck.algorithm,
|
||||
usages: ck.usages,
|
||||
};
|
||||
}
|
||||
const jwk = yield subtle().exportKey('jwk', ck);
|
||||
return {
|
||||
_import: {
|
||||
format: 'jwk',
|
||||
keyData: jwk,
|
||||
},
|
||||
serialized: true,
|
||||
algorithm: ck.algorithm,
|
||||
extractable: ck.extractable,
|
||||
usages: ck.usages,
|
||||
type: ck.type,
|
||||
};
|
||||
}),
|
||||
fromObject: (cks) => __awaiter(this, void 0, void 0, function* () {
|
||||
// if we don't have access to to a real crypto implementation, just return
|
||||
// the serialized crypto key
|
||||
if (crypto.fake) {
|
||||
const newCks = Object.assign({}, cks);
|
||||
delete newCks.serialized;
|
||||
return newCks;
|
||||
}
|
||||
return subtle().importKey(cks._import.format, cks._import.keyData, cks.algorithm, cks.extractable, cks.usages);
|
||||
}),
|
||||
};
|
||||
//# sourceMappingURL=serializeBinary.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"serializeBinary.js","sourceRoot":"","sources":["../src/serializeBinary.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAe,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIlC,MAAM,UAAgB,KAAK,CAAC,IAAY;;QACvC,oEAAoE;QACpE,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACzC,OAAO,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;CAAA;AACD,MAAM,UAAgB,SAAS,CAAC,KAAU,EAAE,sBAAsB,GAAG,IAAI;;QACxE,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,sBAAsB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/E,oEAAoE;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;CAAA;AAED,SAAS,WAAW,CAAC,sBAA+B;IACnD,OAAO;QACN,qBAAqB;QACrB,yBAAyB,CAAC,sBAAsB,CAAC;QACjD,mBAAmB;KACnB,CAAC;AACH,CAAC;AAED,MAAM,qBAAqB,GAAqC;IAC/D,EAAE,EAAE,aAAa;IACjB,MAAM,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,YAAY,WAAW;IAE5C,uGAAuG;IACvG,oEAAoE;IACpE,QAAQ,EAAE,CAAO,EAAe,EAAE,EAAE;QACnC,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAA;IACD,UAAU,EAAE,CAAO,IAAY,EAAE,EAAE;QAClC,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;YACtD,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;SAChC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC,CAAA;CACD,CAAC;AAUF,SAAS,4BAA4B,CAAC,GAAQ;IAC7C,OAAO,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;AACvC,CAAC;AAED,2DAA2D;AAC3D,wDAAwD;AACxD,6EAA6E;AAC7E,SAAS,mBAAmB,CAAC,GAAoB;IAChD,IAAI,GAAG,YAAY,SAAS,EAAE;QAC7B,OAAO,WAAW,CAAC;KACnB;IACD,IAAI,GAAG,YAAY,UAAU,EAAE;QAC9B,OAAO,YAAY,CAAC;KACpB;IACD,IAAI,GAAG,YAAY,iBAAiB,EAAE;QACrC,OAAO,mBAAmB,CAAC;KAC3B;IACD,IAAI,GAAG,YAAY,UAAU,EAAE;QAC9B,OAAO,YAAY,CAAC;KACpB;IACD,IAAI,GAAG,YAAY,WAAW,EAAE;QAC/B,OAAO,aAAa,CAAC;KACrB;IACD,IAAI,GAAG,YAAY,UAAU,EAAE;QAC9B,OAAO,YAAY,CAAC;KACpB;IACD,IAAI,GAAG,YAAY,WAAW,EAAE;QAC/B,OAAO,aAAa,CAAC;KACrB;IACD,IAAI,GAAG,YAAY,YAAY,EAAE;QAChC,OAAO,cAAc,CAAC;KACtB;IACD,IAAI,GAAG,YAAY,YAAY,EAAE;QAChC,OAAO,cAAc,CAAC;KACtB;IACD,IAAI,GAAG,YAAY,QAAQ,EAAE;QAC5B,OAAO,UAAU,CAAC;KAClB;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,yBAAyB,CACjC,cAAuB;IAEvB,OAAO;QACN,EAAE,EAAE,iBAAiB;QACrB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,QAAQ,EAAE,CAAO,GAAoB,EAAE,EAAE;YACxC,IAAI,cAAc,EAAE;gBACnB,2EAA2E;gBAC3E,IAAI,4BAA4B,CAAC,GAAG,CAAC,EAAE;oBACtC,MAAM,GAAG,CAAC,QAAQ,CAAC;iBACnB;aACD;YACD,OAAO;gBACN,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC;gBAC9B,MAAM,EAAE,GAAG,CAAC,MAAM;aACX,CAAC;QACV,CAAC,CAAA;QACD,UAAU,EAAE,CAAO,IAAgC,EAAE,EAAE;YACtD,2BAA2B;YAC3B,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,eAAe,CAAC,CAAC;QAC9C,CAAC,CAAA;KACD,CAAC;AACH,CAAC;AASD,SAAS,OAAO,CAAC,EAAkC;IAClD,OAAQ,EAAyB,CAAC,OAAO,KAAK,SAAS,CAAC;AACzD,CAAC;AAMD,MAAM,mBAAmB,GAAsE;IAC9F,EAAE,EAAE,WAAW;IACf,MAAM,EAAE,CAAC,CAAM,EAAE,EAAE;QAClB,MAAM,QAAQ,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC;QACpC,oDAAoD;QACpD,MAAM,WAAW,GAAG,QAAQ,KAAK,oBAAoB,IAAI,QAAQ,KAAK,cAAc,CAAC;QACrF,MAAM,mBAAmB,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;QACvD,OAAO,WAAW,IAAI,mBAAmB,CAAC;IAC3C,CAAC;IACD,QAAQ,EAAE,CAAO,EAAE,EAAE,EAAE;QACtB,6DAA6D;QAC7D,IAAI,OAAO,CAAC,EAAE,CAAC,EAAE;YAChB,OAAO;gBACN,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,WAAW,EAAE,EAAE,CAAC,WAAW;gBAC3B,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,MAAM,EAAE,EAAE,CAAC,MAAM;aACjB,CAAC;SACF;QACD,MAAM,GAAG,GAAG,MAAM,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChD,OAAO;YACN,OAAO,EAAE;gBACR,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,GAAG;aACZ;YACD,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,IAAI,EAAE,EAAE,CAAC,IAAI;SACb,CAAC;IACH,CAAC,CAAA;IACD,UAAU,EAAE,CAAO,GAAyB,EAAE,EAAE;QAC/C,0EAA0E;QAC1E,4BAA4B;QAC5B,IAAK,MAAc,CAAC,IAAI,EAAE;YACzB,MAAM,MAAM,qBAA8B,GAAG,CAAE,CAAC;YAChD,OAAO,MAAM,CAAC,UAAU,CAAC;YACzB,OAAO,MAAM,CAAC;SACd;QACD,OAAO,MAAM,EAAE,CAAC,SAAS,CACxB,GAAG,CAAC,OAAO,CAAC,MAAM,EAClB,GAAG,CAAC,OAAO,CAAC,OAAc,EAC1B,GAAG,CAAC,SAAgB,EACpB,GAAG,CAAC,WAAW,EACf,GAAG,CAAC,MAAM,CACV,CAAC;IACH,CAAC,CAAA;CACD,CAAC"}
|
3
examples/react-native/src/webview-crypto/webViewWorkerString.d.ts
vendored
Normal file
2135
examples/react-native/src/webview-crypto/webViewWorkerString.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"webViewWorkerString.js","sourceRoot":"","sources":["../src/webViewWorkerString.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+M9B,CAAC;AAEF,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAq4Dd,CAAC"}
|
@ -329,4 +329,24 @@ ul, li {
|
||||
0% {opacity: 1;}
|
||||
50% {opacity: 0.5;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
|
||||
.joy {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
background: url(https://cdn.jsdelivr.net/npm/gun/examples/pop.png) no-repeat;
|
||||
background-position: -2800px 0;
|
||||
pointer-events: none;
|
||||
z-index: 999999999;
|
||||
animation: joy 1s steps(28);
|
||||
}
|
||||
@keyframes joy {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -2800px 0;
|
||||
}
|
||||
}
|
378
gun.js
@ -1,22 +1,22 @@
|
||||
;(function(){
|
||||
|
||||
/* UNBUILD */
|
||||
var root;
|
||||
if(typeof window !== "undefined"){ root = window }
|
||||
if(typeof global !== "undefined"){ root = global }
|
||||
root = root || {};
|
||||
var console = root.console || {log: function(){}};
|
||||
function USE(arg){
|
||||
return arg.slice? USE[R(arg)] : function(mod, path){
|
||||
arg(mod = {exports: {}});
|
||||
USE[R(path)] = mod.exports;
|
||||
}
|
||||
function R(p){
|
||||
return p.split('/').slice(-1).toString().replace('.js','');
|
||||
}
|
||||
}
|
||||
if(typeof module !== "undefined"){ var common = module }
|
||||
/* UNBUILD */
|
||||
/* UNBUILD */
|
||||
var root;
|
||||
if(typeof window !== "undefined"){ root = window }
|
||||
if(typeof global !== "undefined"){ root = global }
|
||||
root = root || {};
|
||||
var console = root.console || {log: function(){}};
|
||||
function USE(arg, req){
|
||||
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
||||
arg(mod = {exports: {}});
|
||||
USE[R(path)] = mod.exports;
|
||||
}
|
||||
function R(p){
|
||||
return p.split('/').slice(-1).toString().replace('.js','');
|
||||
}
|
||||
}
|
||||
if(typeof module !== "undefined"){ var common = module }
|
||||
/* UNBUILD */
|
||||
|
||||
;USE(function(module){
|
||||
// Generic javascript utilities.
|
||||
@ -172,13 +172,13 @@
|
||||
var u, tag = (this.tag || (this.tag = {}))[tag] ||
|
||||
(this.tag[tag] = {tag: tag, to: onto._ = {
|
||||
next: function(arg){ var tmp;
|
||||
if((tmp = this.to)){
|
||||
if((tmp = this.to)){
|
||||
tmp.next(arg);
|
||||
}}
|
||||
}});
|
||||
if(arg instanceof Function){
|
||||
var be = {
|
||||
off: onto.off ||
|
||||
off: onto.off ||
|
||||
(onto.off = function(){
|
||||
if(this.next === onto._.next){ return !0 }
|
||||
if(this === this.the.last){
|
||||
@ -261,14 +261,14 @@
|
||||
if(v === Infinity){ return false } // we want this to be, but JSON does not support it, sad face.
|
||||
if(text_is(v) // by "text" we mean strings.
|
||||
|| bi_is(v) // by "binary" we mean boolean.
|
||||
|| num_is(v)){ // by "number" we mean integers or decimals.
|
||||
|| num_is(v)){ // by "number" we mean integers or decimals.
|
||||
return true; // simple values are valid.
|
||||
}
|
||||
return Val.rel.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
|
||||
return Val.link.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
|
||||
}
|
||||
Val.link = Val.rel = {_: '#'};
|
||||
;(function(){
|
||||
Val.rel.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
|
||||
Val.link.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
|
||||
if(v && v[rel_] && !v._ && obj_is(v)){ // must be an object.
|
||||
var o = {};
|
||||
obj_map(v, map, o);
|
||||
@ -287,7 +287,7 @@
|
||||
}
|
||||
}
|
||||
}());
|
||||
Val.rel.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
|
||||
Val.link.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
|
||||
Type.obj.has._ = '.';
|
||||
var rel_ = Val.link._, u;
|
||||
var bi_is = Type.bi.is;
|
||||
@ -384,10 +384,10 @@
|
||||
State.ify = function(n, k, s, v, soul){ // put a key's state on a node.
|
||||
if(!n || !n[N_]){ // reject if it is not node-like.
|
||||
if(!soul){ // unless they passed a soul
|
||||
return;
|
||||
return;
|
||||
}
|
||||
n = Node.soul.ify(n, soul); // then make it so!
|
||||
}
|
||||
}
|
||||
var tmp = obj_as(n[N_], State._); // grab the states data.
|
||||
if(u !== k && k !== N_){
|
||||
if(num_is(s)){
|
||||
@ -400,7 +400,7 @@
|
||||
return n;
|
||||
}
|
||||
State.to = function(from, k, to){
|
||||
var val = from[k]; // BUGGY!
|
||||
var val = (from||{})[k];
|
||||
if(obj_is(val)){
|
||||
val = obj_copy(val);
|
||||
}
|
||||
@ -473,8 +473,9 @@
|
||||
env.map = env;
|
||||
}
|
||||
if(env.soul){
|
||||
at.rel = Val.rel.ify(env.soul);
|
||||
at.link = Val.link.ify(env.soul);
|
||||
}
|
||||
env.shell = (as||{}).shell;
|
||||
env.graph = env.graph || {};
|
||||
env.seen = env.seen || [];
|
||||
env.as = env.as || as;
|
||||
@ -487,14 +488,16 @@
|
||||
at.env = env;
|
||||
at.soul = soul;
|
||||
if(Node.ify(at.obj, map, at)){
|
||||
//at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
|
||||
env.graph[Val.rel.is(at.rel)] = at.node;
|
||||
at.link = at.link || Val.link.ify(Node.soul(at.node));
|
||||
if(at.obj !== env.shell){
|
||||
env.graph[Val.link.is(at.link)] = at.node;
|
||||
}
|
||||
}
|
||||
return at;
|
||||
}
|
||||
function map(v,k,n){
|
||||
var at = this, env = at.env, is, tmp;
|
||||
if(Node._ === k && obj_has(v,Val.rel._)){
|
||||
if(Node._ === k && obj_has(v,Val.link._)){
|
||||
return n._; // TODO: Bug?
|
||||
}
|
||||
if(!(is = valid(v,k,n, at,env))){ return }
|
||||
@ -503,8 +506,8 @@
|
||||
if(obj_has(v, Node._) && Node.soul(v)){ // ? for safety ?
|
||||
at.node._ = obj_copy(v._);
|
||||
}
|
||||
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
|
||||
at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
|
||||
at.node = Node.soul.ify(at.node, Val.link.is(at.link));
|
||||
at.link = at.link || Val.link.ify(Node.soul(at.node));
|
||||
}
|
||||
if(tmp = env.map){
|
||||
tmp.call(env.as || {}, v,k,n, at);
|
||||
@ -523,14 +526,14 @@
|
||||
}
|
||||
tmp = node(env, {obj: v, path: at.path.concat(k)});
|
||||
if(!tmp.node){ return }
|
||||
return tmp.rel; //{'#': Node.soul(tmp.node)};
|
||||
return tmp.link; //{'#': Node.soul(tmp.node)};
|
||||
}
|
||||
function soul(id){ var at = this;
|
||||
var prev = Val.link.is(at.rel), graph = at.env.graph;
|
||||
at.rel = at.rel || Val.rel.ify(id);
|
||||
at.rel[Val.rel._] = id;
|
||||
var prev = Val.link.is(at.link), graph = at.env.graph;
|
||||
at.link = at.link || Val.link.ify(id);
|
||||
at.link[Val.link._] = id;
|
||||
if(at.node && at.node[Node._]){
|
||||
at.node[Node._][Val.rel._] = id;
|
||||
at.node[Node._][Val.link._] = id;
|
||||
}
|
||||
if(obj_has(graph, prev)){
|
||||
graph[id] = graph[prev];
|
||||
@ -570,13 +573,13 @@
|
||||
}
|
||||
function map(v,k){ var tmp, obj;
|
||||
if(Node._ === k){
|
||||
if(obj_empty(v, Val.rel._)){
|
||||
if(obj_empty(v, Val.link._)){
|
||||
return;
|
||||
}
|
||||
this.obj[k] = obj_copy(v);
|
||||
return;
|
||||
}
|
||||
if(!(tmp = Val.rel.is(v))){
|
||||
if(!(tmp = Val.link.is(v))){
|
||||
this.obj[k] = v;
|
||||
return;
|
||||
}
|
||||
@ -635,7 +638,7 @@
|
||||
dup.to = setTimeout(function(){
|
||||
var now = time_is();
|
||||
Type.obj.map(dup.s, function(it, id){
|
||||
if(opt.age > (now - it.was)){ return }
|
||||
if(it && opt.age > (now - it.was)){ return }
|
||||
Type.obj.del(dup.s, id);
|
||||
});
|
||||
dup.to = null;
|
||||
@ -755,7 +758,7 @@
|
||||
if(!at){
|
||||
if(!(cat.opt||empty).super){
|
||||
ctx.souls[soul] = false;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
at = (ctx.$.get(soul)._);
|
||||
}
|
||||
@ -802,9 +805,25 @@
|
||||
}
|
||||
|
||||
Gun.on.get = function(msg, gun){
|
||||
var root = gun._, soul = msg.get[_soul], node = root.graph[soul], has = msg.get[_has], tmp;
|
||||
var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp;
|
||||
var next = root.next || (root.next = {}), at = next[soul];
|
||||
if(!node || !at){ return root.on('get', msg) }
|
||||
if(obj_has(soul, '*')){ // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
var graph = {};
|
||||
Gun.obj.map(root.graph, function(node, s){
|
||||
if(Gun.text.match(s, soul)){
|
||||
graph[s] = Gun.obj.copy(node);
|
||||
}
|
||||
});
|
||||
if(!Gun.obj.empty(graph)){
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: '*',
|
||||
put: graph,
|
||||
$: gun
|
||||
});
|
||||
}
|
||||
} // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
if(!node){ return root.on('get', msg) }
|
||||
if(has){
|
||||
if(!obj_has(node, has)){ return root.on('get', msg) }
|
||||
node = Gun.state.to(node, has);
|
||||
@ -815,7 +834,7 @@
|
||||
node = Gun.obj.copy(node);
|
||||
}
|
||||
node = Gun.graph.node(node);
|
||||
tmp = at.ack;
|
||||
tmp = (at||empty).ack;
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: 'mem',
|
||||
@ -852,7 +871,7 @@
|
||||
var list_is = Gun.list.is;
|
||||
var text = Gun.text, text_is = text.is, text_rand = text.random;
|
||||
var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy;
|
||||
var state_lex = Gun.state.lex, _soul = Gun.val.rel._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
|
||||
var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
|
||||
var empty = {}, u;
|
||||
|
||||
console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) };
|
||||
@ -863,8 +882,8 @@
|
||||
;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!";
|
||||
Gun.log.once("welcome", "Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!");
|
||||
;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!";
|
||||
|
||||
if(typeof window !== "undefined"){ window.Gun = Gun }
|
||||
|
||||
if(typeof window !== "undefined"){ (window.GUN = window.Gun = Gun).window = window }
|
||||
try{ if(typeof common !== "undefined"){ common.exports = Gun } }catch(e){}
|
||||
module.exports = Gun;
|
||||
|
||||
@ -940,7 +959,6 @@
|
||||
|
||||
function output(msg){
|
||||
var put, get, at = this.as, back = at.back, root = at.root, tmp;
|
||||
if(!msg.I){ msg.I = at.$ }
|
||||
if(!msg.$){ msg.$ = at.$ }
|
||||
this.to.next(msg);
|
||||
if(get = msg.get){
|
||||
@ -948,7 +966,6 @@
|
||||
at.on('in', at);
|
||||
return;
|
||||
}*/
|
||||
//console.log("out!", at.get, get);
|
||||
if(get['#'] || at.soul){
|
||||
get['#'] = get['#'] || at.soul;
|
||||
msg['#'] || (msg['#'] = text_rand(9));
|
||||
@ -1064,7 +1081,7 @@
|
||||
//if(tmp[cat.id]){ return }
|
||||
tmp.is = tmp.is || at.put;
|
||||
tmp[cat.id] = at.put || true;
|
||||
//if(root.stop){
|
||||
//if(root.stop){
|
||||
eve.to.next(msg)
|
||||
//}
|
||||
relate(cat, msg, at, rel);
|
||||
@ -1077,7 +1094,7 @@
|
||||
var tmp = (at.root.$.get(rel)._);
|
||||
if(at.has){
|
||||
from = tmp;
|
||||
} else
|
||||
} else
|
||||
if(from.has){
|
||||
relate(from, msg, from, rel);
|
||||
}
|
||||
@ -1088,13 +1105,12 @@
|
||||
not(at, msg);
|
||||
}
|
||||
tmp = from.id? ((at.map || (at.map = {}))[from.id] = at.map[from.id] || {at: from}) : {};
|
||||
//console.log("REL?", at.id, at.get, rel === tmp.link, tmp.pass || at.pass);
|
||||
if(rel === tmp.link){
|
||||
if(!(tmp.pass || at.pass)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(at.pass){
|
||||
if(at.pass){
|
||||
Gun.obj.map(at.map, function(tmp){ tmp.pass = true })
|
||||
obj_del(at, 'pass');
|
||||
}
|
||||
@ -1117,11 +1133,11 @@
|
||||
if(!(at = next[key])){
|
||||
return;
|
||||
}
|
||||
//if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){
|
||||
//if(data && data[_soul] && (tmp = Gun.val.link.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){
|
||||
// data = tmp.put;
|
||||
//}
|
||||
if(at.has){
|
||||
//if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){
|
||||
//if(!(data && data[_soul] && Gun.val.link.is(data) === Gun.node.soul(at.put))){
|
||||
if(u === at.put || !Gun.val.link.is(data)){
|
||||
at.put = data;
|
||||
}
|
||||
@ -1130,7 +1146,7 @@
|
||||
if(tmp = via.$){
|
||||
tmp = (chain = via.$.get(key))._;
|
||||
if(u === tmp.put || !Gun.val.link.is(data)){
|
||||
tmp.put = data;
|
||||
tmp.put = data;
|
||||
}
|
||||
}
|
||||
at.on('in', {
|
||||
@ -1144,7 +1160,10 @@
|
||||
if(!(at.has || at.soul)){ return }
|
||||
var tmp = at.map, root = at.root;
|
||||
at.map = null;
|
||||
if(at.has){ at.link = null }
|
||||
if(at.has){
|
||||
if(at.dub && at.root.stop){ at.dub = null }
|
||||
at.link = null;
|
||||
}
|
||||
//if(!root.now || !root.now[at.id]){
|
||||
if(!at.pass){
|
||||
if((!msg['@']) && null === tmp){ return }
|
||||
@ -1198,13 +1217,12 @@
|
||||
at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']});
|
||||
return;
|
||||
}
|
||||
msg.$ = at.root.$;
|
||||
Gun.on.put(msg, at.root.$);
|
||||
}
|
||||
var empty = {}, u;
|
||||
var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map;
|
||||
var text_rand = Gun.text.random;
|
||||
var _soul = Gun.val.rel._, node_ = Gun.node._;
|
||||
var _soul = Gun.val.link._, node_ = Gun.node._;
|
||||
})(USE, './chain');
|
||||
|
||||
;USE(function(module){
|
||||
@ -1270,13 +1288,15 @@
|
||||
return at;
|
||||
}
|
||||
function soul(gun, cb, opt, as){
|
||||
var cat = gun._, tmp;
|
||||
if(tmp = cat.soul){ return cb(tmp, as, cat), gun }
|
||||
if(tmp = cat.link){ return cb(tmp, as, cat), gun }
|
||||
var cat = gun._, acks = 0, tmp;
|
||||
if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat), gun }
|
||||
gun.get(function(msg, ev){
|
||||
if(u === msg.put && (tmp = (obj_map(cat.root.opt.peers, function(v,k,t){t(k)})||[]).length) && ++acks < tmp){
|
||||
return;
|
||||
}
|
||||
ev.rid(msg);
|
||||
var at = ((at = msg.$) && at._) || {};
|
||||
tmp = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put);
|
||||
tmp = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put) || at.dub;
|
||||
cb(tmp, as, msg, ev);
|
||||
}, {out: {get: {'.':true}}});
|
||||
return gun;
|
||||
@ -1292,9 +1312,9 @@
|
||||
//else if(!cat.async && msg.put !== at.put && root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);
|
||||
|
||||
|
||||
//root.stop && (root.stop.ID = root.stop.ID || Gun.text.random(2));
|
||||
//root.stop && (root.stop.id = root.stop.id || Gun.text.random(2));
|
||||
//if((tmp = root.stop) && (tmp = tmp[at.id] || (tmp[at.id] = {})) && tmp[cat.id]){ return } tmp && (tmp[cat.id] = true);
|
||||
if(eve.seen && at.id && eve.seen[at.id]){ return eve.to.next(msg) }
|
||||
if(eve.seen && at.id && eve.seen[at.id]){ return eve.to.next(msg) }
|
||||
//if((tmp = root.stop)){ if(tmp[at.id]){ return } tmp[at.id] = msg.root; } // temporary fix till a better solution?
|
||||
if((tmp = data) && tmp[rel._] && (tmp = rel.is(tmp))){
|
||||
tmp = ((msg.$$ = at.root.gun.get(tmp))._);
|
||||
@ -1302,9 +1322,10 @@
|
||||
msg = obj_to(msg, {put: data = tmp.put});
|
||||
}
|
||||
}
|
||||
if((tmp = root.mum) && at.id){
|
||||
if(tmp[at.id]){ return }
|
||||
if(u !== data && !rel.is(data)){ tmp[at.id] = true; }
|
||||
if((tmp = root.mum) && at.id){ // TODO: can we delete mum entirely now?
|
||||
var id = at.id + (eve.id || (eve.id = Gun.text.random(9)));
|
||||
if(tmp[id]){ return }
|
||||
if(u !== data && !rel.is(data)){ tmp[id] = true; }
|
||||
}
|
||||
as.use(msg, eve);
|
||||
if(eve.stun){
|
||||
@ -1326,7 +1347,7 @@
|
||||
//obj.del(map, at); // TODO: Warning: This unsubscribes ALL of this chain's listeners from this link, not just the one callback event.
|
||||
return;
|
||||
}
|
||||
var obj = Gun.obj, obj_has = obj.has, obj_to = Gun.obj.to;
|
||||
var obj = Gun.obj, obj_map = obj.map, obj_has = obj.has, obj_to = Gun.obj.to;
|
||||
var num_is = Gun.num.is;
|
||||
var rel = Gun.val.link, node_soul = Gun.node.soul, node_ = Gun.node._;
|
||||
var empty = {}, u;
|
||||
@ -1364,7 +1385,7 @@
|
||||
});
|
||||
return gun;
|
||||
}
|
||||
as.$ = gun = root.get(as.soul);
|
||||
as.$ = root.get(as.soul);
|
||||
as.ref = as.$;
|
||||
ify(as);
|
||||
return gun;
|
||||
@ -1374,10 +1395,11 @@
|
||||
if(!soul && Gun.val.is(msg.put)){
|
||||
return Gun.log("The reference you are saving is a", typeof msg.put, '"'+ msg.put +'", not a node (object)!');
|
||||
}
|
||||
gun.put(Gun.val.rel.ify(soul), cb, as);
|
||||
gun.put(Gun.val.link.ify(soul), cb, as);
|
||||
}, true);
|
||||
return gun;
|
||||
}
|
||||
if(at.has && (tmp = Gun.val.link.is(data))){ at.dub = tmp }
|
||||
as.ref = as.ref || (root._ === (tmp = at.back))? gun : tmp.$;
|
||||
if(as.ref._.soul && Gun.val.is(as.data) && at.get){
|
||||
as.data = obj_put({}, at.get, as.data);
|
||||
@ -1473,7 +1495,7 @@
|
||||
function soul(id, as, msg, eve){
|
||||
var as = as.as, cat = as.at; as = as.as;
|
||||
var at = ((msg || {}).$ || {})._ || {};
|
||||
id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.rel.is(msg.put || at.put) || (as.via.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous?
|
||||
id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || (as.via.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous?
|
||||
if(eve){ eve.stun = true }
|
||||
if(!id){ // polyfill async uuid for SEA
|
||||
at.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback
|
||||
@ -1519,8 +1541,8 @@
|
||||
as.data = obj_put({}, at.get, as.data);
|
||||
});
|
||||
}
|
||||
tmp = tmp || at.get;
|
||||
at = (at.root.$.get(tmp)._);
|
||||
tmp = tmp || at.soul || at.link || at.dub;// || at.get;
|
||||
at = tmp? (at.root.$.get(tmp)._) : at;
|
||||
as.soul = tmp;
|
||||
data = as.data;
|
||||
}
|
||||
@ -1532,7 +1554,7 @@
|
||||
if(node_ == at.get){
|
||||
as.soul = (at.put||empty)['#'] || at.dub;
|
||||
}
|
||||
as.soul = as.soul || at.soul || at.soul || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
|
||||
as.soul = as.soul || at.soul || at.link || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
|
||||
}
|
||||
if(!as.soul){ // polyfill async uuid for SEA
|
||||
as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback
|
||||
@ -1638,18 +1660,19 @@
|
||||
var opt = this.as, cat = opt.at, gun = msg.$, at = gun._, data = at.put || msg.put, link, tmp;
|
||||
if(tmp = msg.$$){
|
||||
link = tmp = (msg.$$._);
|
||||
if(u === tmp.put){
|
||||
return;
|
||||
if(u !== link.put){
|
||||
data = link.put;
|
||||
}
|
||||
data = tmp.put;
|
||||
}
|
||||
if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) }
|
||||
if(!to && (u === data || at.soul || at.link || (link && !(0 < link.ack)))){
|
||||
if((!to && (u === data || at.soul || at.link || (link && !(0 < link.ack))))
|
||||
|| (u === data && (tmp = (obj_map(at.root.opt.peers, function(v,k,t){t(k)})||[]).length) && (!to && (link||at).ack <= tmp))){
|
||||
tmp = (eve.wait = {})[at.id] = setTimeout(function(){
|
||||
val.call({as:opt}, msg, eve, tmp || 1);
|
||||
}, opt.wait || 99);
|
||||
return;
|
||||
}
|
||||
if(link && u === link.put && (tmp = rel.is(data))){ data = Gun.node.ify({}, tmp) }
|
||||
eve.rid(msg);
|
||||
opt.ok.call(gun || opt.$, data, msg.get);
|
||||
}
|
||||
@ -1711,10 +1734,8 @@
|
||||
gun.map().on(function(data, key, at, ev){
|
||||
var next = (cb||noop).call(this, data, key, at, ev);
|
||||
if(u === next){ return }
|
||||
if(data === next || Gun.is(next)){
|
||||
chain._.on('in', next._);
|
||||
return;
|
||||
}
|
||||
if(data === next){ return chain._.on('in', at) }
|
||||
if(Gun.is(next)){ return chain._.on('in', next._) }
|
||||
chain._.on('in', {get: key, put: next});
|
||||
});
|
||||
return chain;
|
||||
@ -1739,13 +1760,12 @@
|
||||
var gun = this, soul;
|
||||
cb = cb || function(){};
|
||||
opt = opt || {}; opt.item = opt.item || item;
|
||||
if(soul = Gun.node.soul(item)){ return gun.set(gun.back(-1).get(soul), cb, opt) }
|
||||
if(soul = Gun.node.soul(item)){ item = Gun.obj.put({}, soul, Gun.val.link.ify(soul)) }
|
||||
if(!Gun.is(item)){
|
||||
var id = gun.back('opt.uuid')();
|
||||
if(id && Gun.obj.is(item)){
|
||||
return gun.set(gun._.root.$.put(item, id), cb, opt);
|
||||
if(Gun.obj.is(item)){;
|
||||
item = gun.back(-1).get(soul = soul || Gun.node.soul(item) || gun.back('opt.uuid')()).put(item);
|
||||
}
|
||||
return gun.get((Gun.state.lex() + Gun.text.random(7))).put(item, cb, opt);
|
||||
return gun.get(soul || (Gun.state.lex() + Gun.text.random(7))).put(item, cb, opt);
|
||||
}
|
||||
item.get(function(soul, o, msg){
|
||||
if(!soul){ return cb.call(gun, {err: Gun.log('Only a node can be linked! Not "' + msg.put + '"!')}) }
|
||||
@ -1758,10 +1778,12 @@
|
||||
;USE(function(module){
|
||||
if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only. But it would be nice if it could somehow plugin into NodeJS compatible localStorage APIs?
|
||||
|
||||
var root, noop = function(){}, u;
|
||||
if(typeof window !== 'undefined'){ root = window }
|
||||
var store = root.localStorage || {setItem: noop, removeItem: noop, getItem: noop};
|
||||
|
||||
var root, noop = function(){}, store, u;
|
||||
try{store = (Gun.window||noop).localStorage}catch(e){}
|
||||
if(!store){
|
||||
console.log("Warning: No localStorage exists to persist data to!");
|
||||
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
|
||||
}
|
||||
/*
|
||||
NOTE: Both `lib/file.js` and `lib/memdisk.js` are based on this design!
|
||||
If you update anything here, consider updating the other adapters as well.
|
||||
@ -1772,29 +1794,26 @@
|
||||
// See the next 'opt' code below for actual saving of data.
|
||||
var ev = this.to, opt = root.opt;
|
||||
if(root.once){ return ev.next(root) }
|
||||
if(false === opt.localStorage){ return ev.next(root) }
|
||||
opt.file = opt.file || 'gun/';
|
||||
var gap = Gun.obj.ify(store.getItem('gap/'+opt.file)) || {};
|
||||
//if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless!
|
||||
opt.prefix = opt.file || 'gun/';
|
||||
var gap = Gun.obj.ify(store.getItem('gap/'+opt.prefix)) || {};
|
||||
var empty = Gun.obj.empty, id, to, go;
|
||||
// add re-sync command.
|
||||
if(!empty(gap)){
|
||||
root.on('localStorage', function(disk){
|
||||
this.off();
|
||||
var send = {}
|
||||
Gun.obj.map(gap, function(node, soul){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
send[soul] = Gun.state.to(disk[soul], key, send[soul]);
|
||||
});
|
||||
var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {}, send = {};
|
||||
Gun.obj.map(gap, function(node, soul){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
send[soul] = Gun.state.to(disk[soul], key, send[soul]);
|
||||
});
|
||||
setTimeout(function(){
|
||||
root.on('out', {put: send, '#': root.ask(ack), I: root.$});
|
||||
},10);
|
||||
});
|
||||
setTimeout(function(){
|
||||
root.on('out', {put: send, '#': root.ask(ack)});
|
||||
},1);
|
||||
}
|
||||
|
||||
root.on('out', function(msg){
|
||||
if(msg.lS){ return }
|
||||
if(msg.I && msg.put && !msg['@'] && !empty(opt.peers)){
|
||||
if(Gun.is(msg.$) && msg.put && !msg['@'] && !empty(opt.peers)){
|
||||
id = msg['#'];
|
||||
Gun.graph.is(msg.put, null, map);
|
||||
if(!to){ to = setTimeout(flush, opt.wait || 1) }
|
||||
@ -1827,7 +1846,7 @@
|
||||
var flush = function(){
|
||||
clearTimeout(to);
|
||||
to = false;
|
||||
try{store.setItem('gap/'+opt.file, JSON.stringify(gap));
|
||||
try{store.setItem('gap/'+opt.prefix, JSON.stringify(gap));
|
||||
}catch(e){ Gun.log(err = e || "localStorage failure") }
|
||||
}
|
||||
});
|
||||
@ -1837,12 +1856,12 @@
|
||||
var opt = root.opt;
|
||||
if(root.once){ return }
|
||||
if(false === opt.localStorage){ return }
|
||||
opt.file = opt.file || opt.prefix || 'gun/'; // support old option name.
|
||||
opt.prefix = opt.file || 'gun/';
|
||||
var graph = root.graph, acks = {}, count = 0, to;
|
||||
var disk = Gun.obj.ify(store.getItem(opt.file)) || {};
|
||||
var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {};
|
||||
var lS = function(){}, u;
|
||||
root.on('localStorage', disk); // NON-STANDARD EVENT!
|
||||
|
||||
|
||||
root.on('put', function(at){
|
||||
this.to.next(at);
|
||||
Gun.graph.is(at.put, null, map);
|
||||
@ -1870,7 +1889,7 @@
|
||||
return; // Hmm, what if we have peers but we are disconnected?
|
||||
}
|
||||
//console.log("lS get", lex, data);
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.I});
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$ || root.$});
|
||||
};
|
||||
Gun.debug? setTimeout(to,1) : to();
|
||||
});
|
||||
@ -1887,10 +1906,10 @@
|
||||
var ack = acks;
|
||||
acks = {};
|
||||
if(data){ disk = data }
|
||||
try{store.setItem(opt.file, JSON.stringify(disk));
|
||||
}catch(e){
|
||||
Gun.log(err = e || "localStorage failure");
|
||||
root.on('localStorage:error', {err: err, file: opt.file, flush: disk, retry: flush});
|
||||
try{store.setItem(opt.prefix, JSON.stringify(disk));
|
||||
}catch(e){
|
||||
Gun.log(err = (e || "localStorage failure") + " Consider using GUN's IndexedDB plugin for RAD for more storage space, temporary example at https://github.com/amark/gun/blob/master/test/tmp/indexedDB.html .");
|
||||
root.on('localStorage:error', {err: err, file: opt.prefix, flush: disk, retry: flush});
|
||||
}
|
||||
if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers.
|
||||
Gun.obj.map(ack, function(yes, id){
|
||||
@ -1909,6 +1928,10 @@
|
||||
|
||||
function Mesh(ctx){
|
||||
var mesh = function(){};
|
||||
var opt = ctx.opt || {};
|
||||
opt.log = opt.log || console.log;
|
||||
opt.gap = opt.gap || opt.wait || 1;
|
||||
opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB.
|
||||
|
||||
mesh.out = function(msg){ var tmp;
|
||||
if(this.to){ this.to.next(msg) }
|
||||
@ -1916,20 +1939,28 @@
|
||||
if((tmp = msg['@'])
|
||||
&& (tmp = ctx.dup.s[tmp])
|
||||
&& (tmp = tmp.it)
|
||||
&& tmp.mesh){
|
||||
mesh.say(msg, tmp.mesh.via);
|
||||
&& tmp._){
|
||||
mesh.say(msg, (tmp._).via, 1);
|
||||
tmp['##'] = msg['##'];
|
||||
return;
|
||||
}
|
||||
// add hook for AXE?
|
||||
//if (Gun.AXE && opt && opt.super) { Gun.AXE.say(msg, mesh.say, this); return; } // rogowski
|
||||
mesh.say(msg);
|
||||
}
|
||||
|
||||
ctx.on('create', function(root){
|
||||
root.opt.pid = root.opt.pid || Type.text.random(9);
|
||||
this.to.next(root);
|
||||
ctx.on('out', mesh.out);
|
||||
});
|
||||
|
||||
mesh.hear = function(raw, peer){
|
||||
if(!raw){ return }
|
||||
var dup = ctx.dup, id, hash, msg, tmp = raw[0];
|
||||
if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) }
|
||||
try{msg = JSON.parse(raw);
|
||||
}catch(e){}
|
||||
}catch(e){opt.log('DAM JSON parse error', e)}
|
||||
if('{' === tmp){
|
||||
if(!msg){ return }
|
||||
if(dup.check(id = msg['#'])){ return }
|
||||
@ -1941,12 +1972,18 @@
|
||||
(tmp = dup.s)[hash] = tmp[id];
|
||||
}
|
||||
}
|
||||
(msg.mesh = function(){}).via = peer;
|
||||
(msg._ = function(){}).via = peer;
|
||||
if((tmp = msg['><'])){
|
||||
msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
|
||||
(msg._).to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
|
||||
}
|
||||
if(msg.dam){
|
||||
if(tmp = mesh.hear[msg.dam]){
|
||||
tmp(msg, peer, ctx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ctx.on('in', msg);
|
||||
|
||||
|
||||
return;
|
||||
} else
|
||||
if('[' === tmp){
|
||||
@ -1961,21 +1998,21 @@
|
||||
}
|
||||
|
||||
;(function(){
|
||||
mesh.say = function(msg, peer){
|
||||
mesh.say = function(msg, peer, o){
|
||||
/*
|
||||
TODO: Plenty of performance optimizations
|
||||
that can be made just based off of ordering,
|
||||
and reducing function calls for cached writes.
|
||||
*/
|
||||
if(!peer){
|
||||
Type.obj.map(ctx.opt.peers, function(peer){
|
||||
Type.obj.map(opt.peers, function(peer){
|
||||
mesh.say(msg, peer);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen!
|
||||
var tmp, wire = peer.wire || ((opt.wire) && opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen!
|
||||
if(!wire){ return }
|
||||
msh = msg.mesh || empty;
|
||||
msh = (msg._) || empty;
|
||||
if(peer === msh.via){ return }
|
||||
if(!(raw = msh.raw)){ raw = mesh.raw(msg) }
|
||||
if((tmp = msg['@'])
|
||||
@ -1985,31 +2022,32 @@
|
||||
return; // TODO: this still needs to be tested in the browser!
|
||||
}
|
||||
}
|
||||
if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested
|
||||
if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id]) && !o){ return } // TODO: still needs to be tested
|
||||
if(peer.batch){
|
||||
peer.batch.push(raw);
|
||||
return;
|
||||
peer.tail = (peer.tail || 0) + raw.length;
|
||||
if(peer.tail <= opt.pack){
|
||||
peer.batch.push(raw);
|
||||
return;
|
||||
}
|
||||
flush(peer);
|
||||
}
|
||||
peer.batch = [];
|
||||
setTimeout(function(){
|
||||
var tmp = peer.batch;
|
||||
if(!tmp){ return }
|
||||
peer.batch = null;
|
||||
if(!tmp.length){ return }
|
||||
send(JSON.stringify(tmp), peer);
|
||||
}, ctx.opt.gap || ctx.opt.wait || 1);
|
||||
setTimeout(function(){flush(peer)}, opt.gap);
|
||||
send(raw, peer);
|
||||
}
|
||||
|
||||
function flush(peer){
|
||||
var tmp = peer.batch;
|
||||
if(!tmp){ return }
|
||||
peer.batch = peer.tail = null;
|
||||
if(!tmp.length){ return }
|
||||
try{send(JSON.stringify(tmp), peer);
|
||||
}catch(e){opt.log('DAM JSON stringify error', e)}
|
||||
}
|
||||
function send(raw, peer){
|
||||
var wire = peer.wire;
|
||||
try{
|
||||
if(wire.send){
|
||||
if(wire.readyState === wire.OPEN){
|
||||
wire.send(raw);
|
||||
} else {
|
||||
(peer.queue = peer.queue || []).push(raw);
|
||||
}
|
||||
wire.send(raw);
|
||||
} else
|
||||
if(peer.say){
|
||||
peer.say(raw);
|
||||
@ -2020,12 +2058,12 @@
|
||||
}
|
||||
|
||||
}());
|
||||
|
||||
|
||||
;(function(){
|
||||
|
||||
mesh.raw = function(msg){
|
||||
if(!msg){ return '' }
|
||||
var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp;
|
||||
var dup = ctx.dup, msh = (msg._) || {}, put, hash, tmp;
|
||||
if(tmp = msh.raw){ return tmp }
|
||||
if(typeof msg === 'string'){ return msg }
|
||||
if(msg['@'] && (tmp = msg.put)){
|
||||
@ -2038,12 +2076,14 @@
|
||||
msg['#'] = hash || msg['#'];
|
||||
if(put){ (msg = Type.obj.to(msg)).put = _ }
|
||||
}
|
||||
var i = 0, to = []; Type.obj.map(ctx.opt.peers, function(p){
|
||||
var i = 0, to = []; Type.obj.map(opt.peers, function(p){
|
||||
to.push(p.url || p.id); if(++i > 9){ return true } // limit server, fast fix, improve later!
|
||||
}); msg['><'] = to.join();
|
||||
var raw = $(msg);
|
||||
if(u !== put){
|
||||
raw = raw.replace('"'+ _ +'"', put);
|
||||
tmp = raw.indexOf(_, raw.indexOf('put'));
|
||||
raw = raw.slice(0, tmp-1) + put + raw.slice(tmp + _.length + 1);
|
||||
//raw = raw.replace('"'+ _ +'"', put); // https://github.com/amark/gun/wiki/@$$ Heisenbug
|
||||
}
|
||||
if(msh){
|
||||
msh.raw = raw;
|
||||
@ -2064,18 +2104,36 @@
|
||||
function map(k){
|
||||
this.to[k] = this.on[k];
|
||||
}
|
||||
var $ = JSON.stringify, _ = ':])([:'
|
||||
var $ = JSON.stringify, _ = ':])([:';
|
||||
|
||||
}());
|
||||
|
||||
mesh.hi = function(peer){
|
||||
ctx.on('hi', peer);
|
||||
var queue = peer.queue;
|
||||
peer.queue = [];
|
||||
Type.obj.map(queue, function(msg){
|
||||
var tmp = peer.wire || {};
|
||||
if(peer.id || peer.url){
|
||||
opt.peers[peer.url || peer.id] = peer;
|
||||
Type.obj.del(opt.peers, tmp.id);
|
||||
} else {
|
||||
tmp = tmp.id = tmp.id || Type.text.random(9);
|
||||
mesh.say({dam: '?'}, opt.peers[tmp] = peer);
|
||||
}
|
||||
if(!tmp.hied){ ctx.on(tmp.hied = 'hi', peer) }
|
||||
tmp = peer.queue; peer.queue = [];
|
||||
Type.obj.map(tmp, function(msg){
|
||||
mesh.say(msg, peer);
|
||||
});
|
||||
}
|
||||
mesh.bye = function(peer){
|
||||
Type.obj.del(opt.peers, peer.id); // assume if peer.url then reconnect
|
||||
ctx.on('bye', peer);
|
||||
}
|
||||
|
||||
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
|
||||
mesh.hear['?'] = function(msg, peer){
|
||||
if(!msg.pid){ return mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer) }
|
||||
peer.id = peer.id || msg.pid;
|
||||
mesh.hi(peer);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
@ -2119,18 +2177,15 @@
|
||||
opt.WebSocket = websocket;
|
||||
|
||||
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
|
||||
root.on('create', function(at){
|
||||
this.to.next(at);
|
||||
root.on('out', mesh.out);
|
||||
});
|
||||
|
||||
opt.wire = opt.wire || open;
|
||||
function open(peer){
|
||||
if(!peer || !peer.url){ return }
|
||||
var wire = opt.wire;
|
||||
opt.wire = open;
|
||||
function open(peer){ try{
|
||||
if(!peer || !peer.url){ return wire && wire(peer) }
|
||||
var url = peer.url.replace('http', 'ws');
|
||||
var wire = peer.wire = new opt.WebSocket(url);
|
||||
wire.onclose = function(){
|
||||
root.on('bye', peer);
|
||||
opt.mesh.bye(peer);
|
||||
reconnect(peer);
|
||||
};
|
||||
wire.onerror = function(error){
|
||||
@ -2141,15 +2196,14 @@
|
||||
}
|
||||
};
|
||||
wire.onopen = function(){
|
||||
mesh.hi(peer);
|
||||
opt.mesh.hi(peer);
|
||||
}
|
||||
wire.onmessage = function(msg){
|
||||
if(!msg){ return }
|
||||
env.inLength = (env.inLength || 0) + (msg.data || msg).length; // TEMPORARY, NON-STANDARD, FOR DEBUG
|
||||
mesh.hear(msg.data || msg, peer);
|
||||
opt.mesh.hear(msg.data || msg, peer);
|
||||
};
|
||||
return wire;
|
||||
}
|
||||
}catch(e){}}
|
||||
|
||||
function reconnect(peer){
|
||||
clearTimeout(peer.defer);
|
||||
|
2
gun.min.js
vendored
@ -3,10 +3,10 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
Gun.on('opt', function(root){
|
||||
this.to.next(root);
|
||||
if(root.once){ return }
|
||||
console.log("WARNING: `lib/bye` is out of date!");
|
||||
root.on('in', function(msg){
|
||||
if(!msg.peer || !msg.BYE){ return this.to.next(msg) }
|
||||
var peer = msg.peer();
|
||||
//Msg did not have a peer property saved before, so nothing ever went further
|
||||
if(!msg.mesh || !msg.BYE){ return this.to.next(msg) }
|
||||
var peer = msg.mesh.via;
|
||||
(peer.bye = peer.bye || []).push(msg.BYE);
|
||||
})
|
||||
root.on('bye', function(peer){
|
||||
@ -34,4 +34,4 @@ Gun.chain.bye = function(){
|
||||
return gun;
|
||||
}
|
||||
return bye;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
var util = process.memoryUsage;
|
||||
if(!util){ return }
|
||||
|
||||
ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8;
|
||||
ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 1399) * 0.8; // max_old_space_size defaults to 1400 MB. Note: old space !== memory space though.
|
||||
|
||||
setInterval(check, 1000);
|
||||
function check(){
|
||||
|
10
lib/fun.js
Normal file
@ -0,0 +1,10 @@
|
||||
window.fun = function fun(e){ setTimeout(() => {
|
||||
e = e || {}; var $img = $('<div class="joy"></div>')
|
||||
.css({position: 'fixed', width: 100,
|
||||
top: (e.y || e.clientY || (Math.random() * $(window).height()))-50,
|
||||
left: (e.x || e.clientX || e.pageX || (Math.random() * $(window).width()))-50,
|
||||
transform: 'rotate('+(Math.random() * 360)+'deg)'
|
||||
}).appendTo('body');
|
||||
setTimeout(() => { $img.remove() },800);
|
||||
},10)};
|
||||
$(document).on('keyup', fun).on('touchstart', fun).on('mousedown', fun);
|
222
lib/les.js
Normal file
@ -0,0 +1,222 @@
|
||||
;
|
||||
(function() {
|
||||
|
||||
// _ _____ ____ _
|
||||
// | | | ____/ ___| (_)___
|
||||
// | | | _| \___ \ | / __|
|
||||
// | |___| |___ ___) | | \__ \
|
||||
// |_____|_____|____(_)/ |___/
|
||||
// ----------------------------
|
||||
// LES.js (Last rEcently uSed)
|
||||
// ----------------------------
|
||||
// A Small, lightweight, queue-based
|
||||
// Garbage Collector for Gun
|
||||
// Originally By: Collin Conrad (@masterex1000)
|
||||
|
||||
/**
|
||||
*
|
||||
* Usage: require the file in your application
|
||||
*
|
||||
* Gun Params: these are passed to the new gun constructor
|
||||
*
|
||||
* - gc_enable : enables the gc, good if you are running multiple instances of gun, etc... def. true
|
||||
* - gc_delay : sets the amount of time between attempted garbage collections in milliseconds
|
||||
* - gc_info_enable : Enables or Disables the info printout
|
||||
* - gc_info : sets the ~ amount of time between info messages
|
||||
* this is checked everytime the gc is ran
|
||||
* - gc_info_mini : this will use a smaller, less user friendly info printout
|
||||
* - gc_importance_func : This will be the function used for finding the importance of a potental collect
|
||||
* takes the form of func(timestamp, ctime, memoryUsageRatio) {return val}
|
||||
* Collects when returned value is 100
|
||||
*/
|
||||
|
||||
//NOTE: set to false to use require for getting gun DEFUALT: false
|
||||
var USELOCALGUN = false;
|
||||
|
||||
|
||||
//NOTE: adds some debug messages DEFUALT: false
|
||||
var DEBUG = false;
|
||||
|
||||
if(!(typeof window !== "undefined") && USELOCALGUN)
|
||||
console.log("NOTE: You currently have LES.js set to use the 'local' file version of gun, This might crash if set wrong!");
|
||||
|
||||
var Gun = (typeof window !== "undefined") ? window.Gun : (USELOCALGUN ? require('../gun') : require("gun"));
|
||||
|
||||
//Removes a node from the garbage collection until next write
|
||||
Gun.chain.gcDequeue = function() {
|
||||
//console.log(this._.root.dequeueNode);
|
||||
if(this._.root.dequeueNode) { // check that we actually have the dequeue command on this node
|
||||
let ctx = this;
|
||||
|
||||
this.get(function (soul) {
|
||||
ctx._.root.dequeueNode(soul);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
//Puts node at the front for garbage collection, NOTE: only collects when it is hit it's time
|
||||
Gun.chain.gcCollect = function() {
|
||||
if(this._.root.collectNode) { // check that we actually have the dequeue command on this node
|
||||
let ctx = this;
|
||||
|
||||
this.get(function (soul) {
|
||||
ctx._.root.collectNode(soul);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
Gun.on('opt', function(root) {
|
||||
//Setup various options
|
||||
|
||||
const gc_enable = root.opt.gc_enable ? root.opt.gc_enable : true;
|
||||
const gc_delay = root.opt.gc_delay ? root.opt.gc_delay : 1000;
|
||||
|
||||
const gc_info_enable = root.opt.gc_info_enable ? root.opt.gc_info_enable : true;
|
||||
const gc_info = root.opt.gc_info ? root.opt.gc_info : 5000;
|
||||
const gc_info_mini = root.opt.gc_info_mini ? root.opt.gc_info_mini : false;
|
||||
|
||||
//This is long, but it works well
|
||||
const calcRemoveImportance = root.opt.gc_importance_func ? root.opt.gc_importance_func : function (timestamp, ctime, memoryUsageRatio) {
|
||||
var time = (ctime - timestamp) * 0.001;
|
||||
return time * 10 * (memoryUsageRatio * memoryUsageRatio);
|
||||
}
|
||||
|
||||
if(DEBUG) console.log(root.opt);
|
||||
|
||||
this.to.next(root);
|
||||
|
||||
if (root.once)
|
||||
return;
|
||||
if (typeof process == 'undefined')
|
||||
return
|
||||
var mem = process.memoryUsage;
|
||||
|
||||
if(!gc_enable) // exit because the gc is disabled
|
||||
return;
|
||||
|
||||
if (!mem) //exit because we are in the browser
|
||||
return;
|
||||
|
||||
var ev = {}; //stores the environment
|
||||
var empty = {}; //An empty list used to prevent crashes
|
||||
|
||||
//Figure out the most amount of memory we can use. TODO: make configurable?
|
||||
ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8;
|
||||
|
||||
var nodes = {}; //checks if the node already exists
|
||||
var nodesArray = []; //used to easily sort everything and store info about the nodes
|
||||
var memoryUpdate = 0; // last time we printed the current memory stats
|
||||
|
||||
root.dequeueNode = (soul) => { //forward the call to our gc
|
||||
dequeueNode(soul);
|
||||
}
|
||||
|
||||
root.collectNode = (soul) => { //forward the call to our gc
|
||||
collectNode(soul);
|
||||
}
|
||||
|
||||
var check = function() {
|
||||
ev.used = mem().rss / 1024 / 1024; //Contains the amt. of used ram in MB
|
||||
setTimeout(function() { // So we can handle requests etc. before we start collecting
|
||||
GC(ev.used / ev.max); // Calculate the memory ratio, and execute the garbage collector
|
||||
//GC(0.99);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
setInterval(check, gc_delay); // set the garbage collector to run every second
|
||||
|
||||
//Executed every time a node gets modified
|
||||
root.on("put", function(e) {
|
||||
var ctime = Date.now();
|
||||
var souls = Object.keys(e.put || empty); // get all of the nodes in the update
|
||||
for (var i = 0; i < souls.length; i++) { // iterate over them and add them
|
||||
enqueueNode(souls[i], ctime);
|
||||
}
|
||||
});
|
||||
|
||||
//Adds a soul the garbage collectors "freeing" queue
|
||||
function enqueueNode(soul, ctime) {
|
||||
if (nodes[soul] == true) { //The node already exists in the queue
|
||||
var index = nodesArray.findIndex(function(e) {
|
||||
return e[0] === soul;
|
||||
});
|
||||
if (index == -1) {
|
||||
console.error("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated again");
|
||||
return;
|
||||
} else {
|
||||
nodesArray.splice(index, 1); // remove the existing ref. faster than dequeue
|
||||
nodesArray.push([soul, ctime]); // push the new instance
|
||||
}
|
||||
} else {
|
||||
nodesArray.push([soul, ctime]);
|
||||
nodes[soul] = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Removes a node from the queue
|
||||
function dequeueNode(soul) {
|
||||
if (nodes[soul] == true) { //The node already exists in the queue
|
||||
var index = nodesArray.findIndex(function(e) {
|
||||
return e[0] === soul;
|
||||
});
|
||||
if (index != -1) {
|
||||
//nodesArray.splice(index, 1); // remove the existing ref.
|
||||
nodesArray.shift();
|
||||
nodes[soul] = false; // store that we no longer have that node in the queue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Moves a node to the start of the queue
|
||||
function collectNode(soul) {
|
||||
if (nodes[soul] == true) { //The node already exists in the queue
|
||||
var index = nodesArray.findIndex(function(e) {
|
||||
return e[0] === soul;
|
||||
});
|
||||
if (index != -1) {
|
||||
//nodesArray.splice(index, 1); // remove the existing ref.
|
||||
nodesArray.shift(); // WAY faster than splice
|
||||
}
|
||||
nodesArray.unshift([soul, nodesArray[0][1]]); // create a new node with the next nodes time stamp
|
||||
nodes[soul] = true; // store that we no longer have that node in the queue
|
||||
}
|
||||
}
|
||||
|
||||
//The main garbage collecting routine
|
||||
function GC(memRatio) {
|
||||
var curTime = Date.now(); // get the current time
|
||||
|
||||
if (gc_info_enable && curTime - memoryUpdate >= gc_info) { // check if we need to print info
|
||||
if(!gc_info_mini)
|
||||
console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length);
|
||||
else
|
||||
console.log("|GC| %s, Mem Ratio %d, Ram %sMB, Nodes in mem %s, Tracked Nodes %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length, nodesArray.length);
|
||||
memoryUpdate = curTime; // reset the last update time
|
||||
}
|
||||
|
||||
var freed = 0; // Just a nice performance counter
|
||||
|
||||
while (nodesArray.length > 0) { // iterate over all of our nodes
|
||||
var soul = nodesArray[0][0];
|
||||
var nts = nodesArray[0][1];
|
||||
if (DEBUG)
|
||||
console.log("Soul: " + soul + " | Remove Importance: " + calcRemoveImportance(nts, curTime, memRatio) +
|
||||
" | Memory Ratio: " + memRatio + " | Time Existed: " + (curTime - nts) / 1000);
|
||||
if (calcRemoveImportance(nodesArray[0][1], curTime, memRatio) >= 100) {
|
||||
root.gun.get(nodesArray[0][0]).off(); //Remove the node
|
||||
delete nodes[nodesArray[0][0]]; // remove the lookup value
|
||||
//nodesArray.splice(0, 1);
|
||||
nodesArray.shift();
|
||||
freed++; // add one to our perf counter
|
||||
} else
|
||||
break; // Break out of the loop because we don't have any more nodes to free
|
||||
}
|
||||
if (freed > 0)
|
||||
console.log("|GC| Removed %s nodes in %s seconds-----------------------------------------------------------------", freed, (Date.now() - curTime) * 0.001);
|
||||
}
|
||||
|
||||
function round(value, decimals) { //a basic rounding function
|
||||
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
|
||||
}
|
||||
});
|
||||
}());
|
360
lib/meta.js
Normal file
@ -0,0 +1,360 @@
|
||||
$(function(){
|
||||
var m = window.meta = {edit:[], os:{}}, ua = '', u;
|
||||
try{ua = navigator.userAgent.toLowerCase()}catch(e){}
|
||||
m.os.is = {
|
||||
win: (ua.search("win") >= 0)? "windows":false,
|
||||
lin: (ua.search("linux") >= 0)? "linux":false,
|
||||
mac: (ua.search("mac") >= 0)? "macintosh":false,
|
||||
and: (ua.search("android") >= 0)? "android":false,
|
||||
ios: (ua.search('ipod') >= 0
|
||||
|| ua.search('iphone') >= 0
|
||||
|| ua.search('ipad') >= 0)? "ios":false
|
||||
}
|
||||
var k = m.key = {ctrl: 17, cmd: 91};
|
||||
k.meta = (m.os.is.win||m.os.is.lin||m.os.is.and)? k.ctrl : k.cmd;
|
||||
k.down = function(eve){
|
||||
if($(eve.target).is('input') || eve.repeat){ return }
|
||||
(k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
if(!eve.fake && eve.which === k.last){ return }
|
||||
if(k.meta === (k.last = eve.which)){ k.down.meta = m.flip(k.wipe()) || true }
|
||||
if(m.flip.is()){
|
||||
(k.combo || (k.combo = [])).push(eve.which);
|
||||
m.check('on', eve.which, k.at || (k.at = m.edit));
|
||||
}
|
||||
if(eve.metaKey && (k.meta !== eve.which)){ k.up(eve) } // on some systems, meta hijacks keyup
|
||||
}
|
||||
k.up = function(eve){ var tmp;
|
||||
if($(eve.target).is('input')){ return }
|
||||
k.eve = m.eve = eve;
|
||||
k.last = null;
|
||||
eve.which = eve.which || eve.fake || eve.keyCode;
|
||||
if(m.flip.is()){ m.check('up', eve.which) }
|
||||
if(tmp = (k.meta === eve.which)){ k.down.meta = false }
|
||||
if(tmp && k.at === m.edit){ k.wipe() }
|
||||
if(27 === eve.which){ return m.flip(false) }
|
||||
}
|
||||
m.flip = function(tmp, aid){
|
||||
if(aid){
|
||||
m.flip.aid = true;
|
||||
setTimeout(function(){$(document).one('click',function(eve){m.flip(m.flip.aid = false)})},250); // ugly but important for visual aid.
|
||||
}
|
||||
var board = $('#meta .meta-menu');
|
||||
((tmp === false) || (!tmp && board.is(':visible')))?
|
||||
board.addClass('meta-none')
|
||||
: board.removeClass('meta-none');
|
||||
}
|
||||
m.flip.is = function(){
|
||||
if(m.flip.aid && ((m.eve||{}).fake || k.at !== m.edit)){ m.flip.aid = false }
|
||||
return !m.flip.aid && $('#meta .meta-menu').is(':visible');
|
||||
}
|
||||
m.flip.wait = 500;
|
||||
m.check = function(how, key, at){
|
||||
at = k.at || m.edit;
|
||||
//m.list(at);
|
||||
var edit = at[key], tmp;
|
||||
if(!edit){ return }
|
||||
if(k.eve && k.eve.preventDefault){ k.eve.preventDefault() }
|
||||
if(edit[how]){
|
||||
edit[how](m.eve);
|
||||
if(k.at !== m.edit && 'up' === how){
|
||||
if(k.down.meta){ m.list(k.at = m.edit) }
|
||||
else { k.wipe() }
|
||||
}
|
||||
}
|
||||
if('up' != how){ return }
|
||||
edit.back = at;
|
||||
m.list(edit, at);
|
||||
}
|
||||
m.list = function(at){
|
||||
var l = [];
|
||||
$.each(at, function(i,k){ 'back' != i && k.combo && l.push(k) });
|
||||
if(!l.length){ return }
|
||||
k.at = at;
|
||||
l = l.sort(function(a,b){
|
||||
a = a.combo.slice(-1)[0] || 0;
|
||||
if(a.length){ a = a.toUpperCase().charCodeAt(0) }
|
||||
b = b.combo.slice(-1)[0] || 0;
|
||||
if(b.length){ b = b.toUpperCase().charCodeAt(0) }
|
||||
return (a < b)? -1 : 1;
|
||||
});
|
||||
var $ul = $('#meta .meta-menu ul')
|
||||
$ul.children('li').addClass('meta-none').hide(); setTimeout(function(){ $ul.children('.meta-none').remove() },250); // necessary fix for weird bug glitch
|
||||
$.each(l, function(i, k){
|
||||
$ul.append($('<li>').text(k.name));
|
||||
});
|
||||
if(!at.back){ return }
|
||||
$ul.append($('<li>').html('←').one('click', function(){ m.list(k.at = at.back) }));
|
||||
}
|
||||
m.ask = function(help, cb){
|
||||
var $ul = $('#meta .meta-menu ul').empty();
|
||||
var $put = $('<input>').attr('id', 'meta-ask').attr('placeholder', help);
|
||||
var $form = $('<form>').append($put).on('submit', function(eve){
|
||||
eve.preventDefault();
|
||||
cb($put.val());
|
||||
$li.remove();
|
||||
k.wipe();
|
||||
});
|
||||
var $li = $('<li>').append($form);
|
||||
$ul.append($li);
|
||||
$put.focus();
|
||||
}
|
||||
k.wipe = function(){
|
||||
k.combo = [];
|
||||
m.flip(false);
|
||||
m.flip.aid = false;
|
||||
m.list(k.at = m.edit);
|
||||
};
|
||||
$(document).on('keydown', k.down).on('keyup', k.up);
|
||||
m.tap = {};
|
||||
m.tap.select = function(eve){
|
||||
m.tap.range = null;
|
||||
if(!(m.tap.text()||'').trim()){
|
||||
if(m.tap.was){
|
||||
m.tap.was = null;
|
||||
m.flip(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
m.flip(m.tap.range = monotype((eve||{}).target), m.tap.was = true);
|
||||
}
|
||||
m.tap.text = function(tmp){
|
||||
return ((tmp = window.getSelection) && tmp().toString()) ||
|
||||
((tmp = document.selection) && tmp.createRange().text) || '';
|
||||
}
|
||||
$(window).on('blur', k.wipe).on('focus', k.wipe);
|
||||
$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.tap.select);
|
||||
//.on('keydown', '[contenteditable=true]', function(e){});
|
||||
$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
|
||||
$(document).on('click', '#meta .meta-menu li', function(eve){
|
||||
if(m.tap.stun){ return m.tap.stun = false }
|
||||
if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return }
|
||||
eve.tap = true;
|
||||
k.down(eve);
|
||||
k.up(eve);
|
||||
});
|
||||
meta.edit = function(edit){
|
||||
var tmp = edit.combow = [];
|
||||
$.each(edit.combo || (edit.combo = []), function(i,k){
|
||||
if(!k || !k.length){ return }
|
||||
tmp.push(k.toUpperCase().charCodeAt(0));
|
||||
});
|
||||
var at = meta.edit, l = edit.combo.length;
|
||||
$.each(tmp, function(i,k){ at = at[k] = (++i >= l)? edit : at[k] || {} });
|
||||
edit.combow = edit.combow.join(',');
|
||||
m.list(meta.edit);
|
||||
}
|
||||
meta.text = {zws: '​'};
|
||||
meta.text.editor = function(opt, as){ var tmp;
|
||||
if(!opt){ return }
|
||||
opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt};
|
||||
var r = opt.range = opt.range || m.tap.range || monotype(), cmd = opt.edit;
|
||||
as = opt.as = opt.as || as;
|
||||
if(cmd && document.execCommand){
|
||||
r.restore();
|
||||
if(document.execCommand(cmd, null, as||null)){ return }
|
||||
}
|
||||
if(!opt.tag){ return }
|
||||
opt.tag = $(opt.tag);
|
||||
opt.name = opt.name || opt.tag.prop('tagName');
|
||||
if((tmp = $(r.get()).closest(opt.name)).length){
|
||||
if(r.s === r.e){
|
||||
tmp.after(meta.text.zws);
|
||||
r = r.select(monotype.next(tmp[0]),1);
|
||||
} else {
|
||||
tmp.contents().unwrap(opt.name);
|
||||
}
|
||||
} else
|
||||
if(r.s === r.e){
|
||||
r.insert(opt.tag);
|
||||
r = r.select(opt.tag);
|
||||
} else {
|
||||
r.wrap(opt.tag);
|
||||
}
|
||||
r.restore();
|
||||
opt.range = null;
|
||||
if(m.tap.range){ m.tap.range = monotype() }
|
||||
}
|
||||
;(function(){try{
|
||||
/* UI */
|
||||
if(meta.css){ return }
|
||||
var $m = $('<div>').attr('id', 'meta');
|
||||
$m.append($('<span>').text('+').addClass('meta-start'));
|
||||
$m.append($('<div>').addClass('meta-menu meta-none').append('<ul>'));
|
||||
$(document.body).append($m);
|
||||
css({
|
||||
'#meta': {
|
||||
display: 'block',
|
||||
position: 'fixed',
|
||||
bottom: '2em',
|
||||
right: '2em',
|
||||
background: 'white',
|
||||
'font-size': '18pt',
|
||||
'font-family': 'Tahoma, arial',
|
||||
'box-shadow': '0px 0px 1px #000044',
|
||||
'border-radius': '1em',
|
||||
'text-align': 'center',
|
||||
'z-index': 999999,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
width: '2em',
|
||||
height: '2em',
|
||||
opacity: 0.7,
|
||||
color: '#000044',
|
||||
overflow: 'visible',
|
||||
transition: 'all 0.2s ease-in'
|
||||
},
|
||||
'#meta .meta-none': {display: 'none'},
|
||||
'#meta span': {'line-height': '2em'},
|
||||
'#meta .meta-menu': {
|
||||
background: 'rgba(0,0,0,0.1)',
|
||||
width: '12em',
|
||||
right: '-2em',
|
||||
bottom: '-2em',
|
||||
overflow: 'visible',
|
||||
position: 'absolute',
|
||||
'overflow-y': 'scroll',
|
||||
'text-align': 'right',
|
||||
'min-height': '20em',
|
||||
height: '100vh'
|
||||
},
|
||||
'#meta .meta-menu ul': {
|
||||
padding: 0,
|
||||
margin: '1em 1em 2em 0',
|
||||
'list-style-type': 'none'
|
||||
},
|
||||
'#meta .meta-menu ul li': {
|
||||
display: 'block',
|
||||
background: 'white',
|
||||
padding: '0.5em 1em',
|
||||
'border-radius': '1em',
|
||||
'margin-left': '0.25em',
|
||||
'margin-top': '0.25em',
|
||||
'float': 'right'
|
||||
},
|
||||
'#meta a': {color: 'black'},
|
||||
'#meta:hover': {opacity: 1},
|
||||
'#meta .meta-menu ul:before': {
|
||||
content: "' '",
|
||||
display: 'block',
|
||||
'min-height': '15em',
|
||||
height: '50vh'
|
||||
},
|
||||
'#meta li': {
|
||||
background: 'white',
|
||||
padding: '0.5em 1em',
|
||||
'border-radius': '1em',
|
||||
'margin-left': '0.25em',
|
||||
'margin-top': '0.25em',
|
||||
'float': 'right'
|
||||
},
|
||||
'#meta:hover .meta-menu': {display: 'block'}
|
||||
});
|
||||
function css(css){
|
||||
var tmp = '';
|
||||
$.each(css, function(c,r){
|
||||
tmp += c + ' {\n';
|
||||
$.each(r, function(k,v){
|
||||
tmp += '\t'+ k +': '+ v +';\n';
|
||||
});
|
||||
tmp += '}\n';
|
||||
});
|
||||
(node = document.createElement('style')).innerHTML = tmp;
|
||||
document.body.appendChild(node);
|
||||
}
|
||||
}catch(e){}}());
|
||||
;(function(){
|
||||
// on fires when shortcut keydowns or on touch after command selected and then touchdown
|
||||
meta.edit({
|
||||
name: "Bold",
|
||||
combo: ['B'],
|
||||
on: function(e){
|
||||
meta.text.editor('bold');
|
||||
},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Italic",
|
||||
combo: ['I'],
|
||||
on: function(e){
|
||||
meta.text.editor('italic');
|
||||
},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Underline",
|
||||
combo: ['U'],
|
||||
on: function(e){
|
||||
meta.text.editor('underline');
|
||||
},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "linK",
|
||||
combo: ['K'],
|
||||
up: function(e){
|
||||
var range = meta.tap.range || monotype();
|
||||
meta.ask('Paste or type link...', function(url){
|
||||
meta.text.editor({tag: $('<a href="'+url+'">link</a>'), edit: url? 'createLink' : 'unlink', as: url, range: range});
|
||||
})
|
||||
},
|
||||
on: function(){}
|
||||
});
|
||||
meta.edit({name: "aliGn", combo: ['G']});
|
||||
meta.edit({
|
||||
name: "Left",
|
||||
combo: ['G','L'],
|
||||
on: function(e){ meta.text.editor('justifyLeft') },
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Right",
|
||||
combo: ['G','R'],
|
||||
on: function(e){ meta.text.editor('justifyRight') },
|
||||
up: function(){ }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Middle",
|
||||
combo: ['G','M'],
|
||||
on: function(e){ meta.text.editor('justifyCenter') },
|
||||
up: function(){ }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Justify",
|
||||
combo: ['G','J'],
|
||||
on: function(e){ meta.text.editor('justifyFull') },
|
||||
up: function(){}
|
||||
});
|
||||
// Align Number
|
||||
// Align Points
|
||||
// Align Strike
|
||||
meta.edit({name: "Size", combo: ['S']});
|
||||
meta.edit({
|
||||
name: "Small",
|
||||
combo: ['S','S'],
|
||||
on: function(e){ meta.text.editor('fontSize', 2) },
|
||||
up: function(){ }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Normal",
|
||||
combo: ['S','N'],
|
||||
on: function(e){ meta.text.editor('fontSize', 5) },
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Header",
|
||||
combo: ['S','H'],
|
||||
on: function(e){ meta.text.editor('fontSize', 6) },
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Title",
|
||||
combo: ['S','T'],
|
||||
on: function(e){ meta.text.editor('fontSize', 7) },
|
||||
up: function(){}
|
||||
});
|
||||
// Size Spacing
|
||||
// Size Super
|
||||
// Size Sub
|
||||
meta.edit({name: "Edit", combo: ['E']});
|
||||
}());
|
||||
});
|