Author here. Amusingly, I wanted to link to the HN discussion on the page, but couldn't figure out how to... I don't think it's possible! Something I hadn't considered until just now with a content addressable web is there are no cycles in the links.
Edit: Another amusing anecdote. I've been following this on log2viz (the heroku realtime performance monitoring tool), and was aghast to see high response times and memory usage. Then I realized I was actually looking at the dashboard for one of my rails apps! Phoenix is sitting pretty at about 35MB memory usage, and a median response time of 5ms, so far.
Are you able to adjust the url of the HN submission? I don't feel like creating one just to check, but that makes it easy to link the discussion, create the discussion before the page.
No, but that would be the way to do it, for sure. There's a link to "edit" my submission, but the form it takes me to only allows updating the title. It displays the URL as ordinary text, rather than a text input.
An idea to make this(and the editable content suggestion in another comment) possible could be to add something to the protocol to define "previous versions" sha hashes.
If you want to edit a page then create a new page which includes the sha hash of the previous versions. If you get a request for the content of a sha hash of an old version, you could suggest your sha hash as an updated version.
Hmm, ok, but that is just an implementation detail. I just see a really simlple service here that could become really beautiful if one could manipulate the content, once it is in your browser, so the next time it is passed along, it will have evolved. Into what? I don't know. But what if I seeded the system with an image, a simple drawing or a shape, vector or whatever, and then just sat back, observed how other people took it further. Like graffiti. Forking of content could be insteresting. Or a github, but a peer-to-peer version?
Doesn't git use hashes also? The old hash could redirect to the new "commit" hash, keeping the cycle and allowing for updates at the same time. One of those updates could be the page "changelog".
Yes, git does use hashes, but git similarly doesn't work in that manner for the same reason. Git commits can only point to commits in the past and not future commits. It is not possible to update old commits like you suggest.
The HEAD of a repository is like a pointer to the hash of a commit. You may think of HEAD like a repointable alias. `cat .git/refs/heads/master` in any of your git repositories to see what I mean.
It changes the content of the commit (by iterating the hash in the commit message itself) until the hash of the child commit matches. A big part of the trick is that it only looks at a prefix of the hash, so the search space is much smaller than the full SHA1 hash.
This is a problem that Freenet solved a long time ago. It means you need public-key cryptography rather than hashes for security, but they support updating pages--and, of course, any and all leaf content can still use hashes for better cacheability.
It's worth noting that WebRTC still requires a server of SOME sort -- typically you want a "signaling" server, and you need at least a STUN server to pierce firewalls, though the latter can be found for free.
And some corporate networks are too restrictive to be pierced by STUN, which means you need a TURN server, which is a relay server.
But yes, 98% of the time, WebRTC can go directly browser to browser. As long as neither browser is Internet Explorer. Sigh.
Is it even possible to open a socket from a browser to another browser directly? I was under the impression that was restricted for security reasons (websites becoming botnets and such).
I once solved a similar problem by creating a link at tinyurl and then updating that link to point to whatever the name of my uploaded file had become :)
the hash is a hash of the content itself, so the link is immutable - if you changed the content the link wouldn't be pointing to the same thing anymore.
The web-pages are recognized by their hash, so you can't change them after you setup the page. The problem is that you would have to supply HN with the link to the page, and then go back and edit the page to include the link to the new HN article. Since you can't go back and edit the page, you can't include the link.
Would a page be able to leave and come back into the network by having a computer that's offline but viewing the page and then comes back? i.e. is there anything to prevent it?
im not 100% sure how this all fits together, but you should be able to recreate a page, so long as the content was exactly the same, and therefor produced the same hash.
So you could set it up to automatically recreate the page when your machine comes back online.
Not quite but I assumed similarly. I'm wondering if it'll connect to the peers automatically after coming back online if just left in the browser. If it did then it'd be possible to keep a page unpublished except when asked for through another channel. It's definitely a really interesting idea to play with. It makes me wonder if it could be used to create a nicer interface for things like Freenet by doing more clientside these days.
I've actually seen people successfully get a tweet to link to itself through trial and error. You can try and guess the IDs and you will eventually get it right.
I just used firebug to alter the page in my browser. I changed the first heading from "This page exists only if someone is looking at it" to "What happens if I use Firebug to alter this page in-situ. Do I end up with malware?".
Will this change propagate? Has anyone yet seen this modified page in their own browser?
Edit:
From the original page: "The server double checks the hash of the content it gets and then passes it along to the new person." I guess the answer is that the change won't propagate?
Correct, the change won't propagate for the reasons you say. (See source [0]). Also, though, note that the content comes to you as a blob of JSON, which gets rendered into your page, and you respond to future content requests with that blob of JSON, rather than the HTML itself.
>and you shouldn't be trusting me any more than any other random internet person.
Because I did trust you more than most other random internet persons, I trusted your javascript by temporarily whitelisting it in my browser to view the contents. :)
If you ditched the hash that checks the content and made the whole page 'content-editable' (maybe with something that stripped certain tags like images and video for obvious reasons), that might be fun. :)
Ha, that's a fun idea. I imagine it would regress to a lot of inappropriate ASCII art pretty quickly, though...
The SHA-256 checksum is actually part of what makes it very interesting to me, though. Since the content of the page is guaranteed by the location of it, it's kind of a shared web that anyone can help host.
Very cool! Interesting to see your findings. Maybe the browser is capable already of simplifying p2p file sharing. It would be good to get rid of todays torrent clients and have your browser run some slick p2p service instead that also serves as a convenient way of sharing or sending files with collegues and friends. I also really love the idea of tossing web content around (between) peers like that. Good work, so far. Don't think you're done yet.
Very cool stuff. I wonder if it would be possible to host an entire webapp with sockets/rtc. I don't see why not, but it you'd have to re-invent decades worth of architecture built around http.
True, and a very clear way of putting it. Interestingly, since Erlang is so well-suited for distributed computing, and Phoenix (the web framework I'm using) has been built to take advantage of that, it wouldn't be too hard to let someone else spin up this same service and take part in distributing the content.
Off the top of my head, the only thing that wouldn't work is the "Currently Viewing" counter, which relies on this all running on a single heroku dyno. Otherwise, the socket messages are routed over a distributed PubSub layer, which should be pretty easy to tap into.
It's a cool idea. What do you think about running it from an Android? (Isn't there an Apache APK?) So you can only view the page while connected to the phone's hotspot?
Very nice idea and I'm sure that it's a great way to play with Elixir/a platform. Well done!
Two questions:
1)
You talk about P2P uses, but would it be feasible to 'seed' a true P2P net? A site that delivers the application, and everything from there is P2P vs. 'ask the server so that the server asks potential peers (clients?)'?
2)
I got this at the top:
Connecting to websocket.
Connected!
Listening for content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838
Requesting content.
Received content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838
Received content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838
Standing by... ready to share this content!
Two answers for the hash? Intentional? Fine? If that happens quite a lot, you might waste more bandwidth/resources than necessary in your experiment?
For (1) I'm not sure. I'm primarily a backend dev, so this was partly an experiment for me to play with the front end, too. I kind of hope javascript is not able to connect "sideways" to other ordinary browsers. I would think they'd need to be running some sort of server, which I don't think the browser can get going. Would be happy to learn more about this from someone more knowledgeable.
Regarding (2), you should have seen my first approach: Every new client broadcasted a request for the content, and everyone with it responded! Now that was a waste of bandwidth.
But what I've done here is I send the request for content out to everyone with it, with a probability of 1/N, where N is roughly the number of people with it. So in your case, it looks like it got sent to two folks. Sometimes it gets sent to none, in which case the client will retry in 2 seconds.
It was a little tricky to figure out since phoenix runs every socket connection in its own erlang process (great for robustness and concurrency, but a real mind bender if you're not used to it). So this probabilistic approach was the best I could come up with, instead of having some master process select the right person to send the request to.
As the page is content-addressed, it can only change the content by changing the address, thus creating a whole new webpage - address and content, after all, define the resource.
I think the concept is akin to a beach ball that is passed from hand to hand. It only exists one instance of it. With a webserver, a new instance is created for each user viewing the page.
An attempt (copy paste really) to try and keep the window open and the content alive. Also, a request for the root/homepage could be funny if it was meta [0].
Apparently it simply try to open a bunch of modal window to close. Chrome is smarter enough to figure that out, and there's only about five windows before the script is killed.
This is a fantastic example of using Phoenix channels! For those interested in how channels work, check out my ElixirConfEU Phoenix keynote where I give an overview:
I once implemented a crude but serverless P2P in JavaScript by using pulse-width-modulating information inside bandwidth usage; anyone on the same Wi-Fi frequency would then be able to stream some arbitrary fixed-bitrate content and observe the drops in their bandwidth throughput to pick up the modulated information. But it was hellishly slow (a couple of bytes a second at best, a couple of bits at worst), and didn't work as soon as there were 3 devices on the frequency.
Would be interested to explore other ways to make pure-JS mesh networking happen. I've thought of using the JavaScript image pinging trick to "port scan" the entire subnet for peers, and communicate by "mildly DDoSing" each other with pings, but haven't actually tried yet.
Another potential method to pure-JS P2P is by using the microphone and speaker and building a mesh network at inaudible frequencies but this requires microphone permissions and won't work beyond the same room, and would be only several hundred bytes per second at best.
Interesting, this is like a P2P Snapchat for text. Or no. Better said, I am having trouble trying to associate this with something that exists already.
Feross has built the thing the author talks about, a Bittorrent client in the browser called WebTorrent, it is super awesome and incredibly useful for sending files, check it out at: http://instant.io !
170 comments
[ 5.3 ms ] story [ 221 ms ] threadEdit: Another amusing anecdote. I've been following this on log2viz (the heroku realtime performance monitoring tool), and was aghast to see high response times and memory usage. Then I realized I was actually looking at the dashboard for one of my rails apps! Phoenix is sitting pretty at about 35MB memory usage, and a median response time of 5ms, so far.
The HEAD of a repository is like a pointer to the hash of a commit. You may think of HEAD like a repointable alias. `cat .git/refs/heads/master` in any of your git repositories to see what I mean.
Not true! With git time-travel, you can refer to a future commits in the commit message. Eg:
https://github.com/hundt/git-time-travel:p
For anyone curious, this uses the same idea as the "guess-and-check" approach spullara mentioned: https://news.ycombinator.com/item?id=953569
It changes the content of the commit (by iterating the hash in the commit message itself) until the hash of the child commit matches. A big part of the trick is that it only looks at a prefix of the hash, so the search space is much smaller than the full SHA1 hash.
And some corporate networks are too restrictive to be pierced by STUN, which means you need a TURN server, which is a relay server.
But yes, 98% of the time, WebRTC can go directly browser to browser. As long as neither browser is Internet Explorer. Sigh.
http://skylink.io/plugin/
This library they also have makes WebRTC cross browser compatible.
https://github.com/Temasys/AdapterJS
If all popular torrent sites moved to in-browser downloads over WebRTC, virtually everybody would move away from IE :)
So you could set it up to automatically recreate the page when your machine comes back online.
is that what you meant?
Will this change propagate? Has anyone yet seen this modified page in their own browser?
Edit:
From the original page: "The server double checks the hash of the content it gets and then passes it along to the new person." I guess the answer is that the change won't propagate?
[0] https://github.com/losvedir/ephemeral2/blob/master/web/chann...
>and you shouldn't be trusting me any more than any other random internet person.
Because I did trust you more than most other random internet persons, I trusted your javascript by temporarily whitelisting it in my browser to view the contents. :)
If you ditched the hash that checks the content and made the whole page 'content-editable' (maybe with something that stripped certain tags like images and video for obvious reasons), that might be fun. :)
The SHA-256 checksum is actually part of what makes it very interesting to me, though. Since the content of the page is guaranteed by the location of it, it's kind of a shared web that anyone can help host.
See: http://www.html5rocks.com/en/tutorials/webrtc/basics/
http://icecomm.io/
Keep going!
True, and a very clear way of putting it. Interestingly, since Erlang is so well-suited for distributed computing, and Phoenix (the web framework I'm using) has been built to take advantage of that, it wouldn't be too hard to let someone else spin up this same service and take part in distributing the content.
Off the top of my head, the only thing that wouldn't work is the "Currently Viewing" counter, which relies on this all running on a single heroku dyno. Otherwise, the socket messages are routed over a distributed PubSub layer, which should be pretty easy to tap into.
That would make it even more etheral.
like if
server 1abcdef is managing 300 sockets server 2ghijkl is managing 200 sockets
then you just add those on the frontend
In that sense there needn't be a single service. Just a bunch of rendevous points for browsers-with-content to connect and announce what they have.
Two questions:
1) You talk about P2P uses, but would it be feasible to 'seed' a true P2P net? A site that delivers the application, and everything from there is P2P vs. 'ask the server so that the server asks potential peers (clients?)'?
2)
I got this at the top:
Connecting to websocket. Connected! Listening for content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838 Requesting content. Received content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838 Received content for hash 2bbbf21959178ef2f935e90fc60e5b6e368d27514fe305ca7dcecc32c0134838 Standing by... ready to share this content!
Two answers for the hash? Intentional? Fine? If that happens quite a lot, you might waste more bandwidth/resources than necessary in your experiment?
For (1) I'm not sure. I'm primarily a backend dev, so this was partly an experiment for me to play with the front end, too. I kind of hope javascript is not able to connect "sideways" to other ordinary browsers. I would think they'd need to be running some sort of server, which I don't think the browser can get going. Would be happy to learn more about this from someone more knowledgeable.
Regarding (2), you should have seen my first approach: Every new client broadcasted a request for the content, and everyone with it responded! Now that was a waste of bandwidth.
But what I've done here is I send the request for content out to everyone with it, with a probability of 1/N, where N is roughly the number of people with it. So in your case, it looks like it got sent to two folks. Sometimes it gets sent to none, in which case the client will retry in 2 seconds.
It was a little tricky to figure out since phoenix runs every socket connection in its own erlang process (great for robustness and concurrency, but a real mind bender if you're not used to it). So this probabilistic approach was the best I could come up with, instead of having some master process select the right person to send the request to.
http://ephemeralp2p.durazo.us/82d78987fd1cd530302b81d5643739...
This is a test page with embedded media via base64 encoding. This shouldn't touch the server, so hopefully no bottlenecks for this page either :)
http://ephemeralp2p.durazo.us/5264b0eea08fc0f6c8c164815c30dd...
[0] https://github.com/losvedir/ephemeral2/blob/master/web/chann...
If the content you get sent doesn't match that fingerprint, it will reject it.
I think a better title would be "This page only exists AS LONG AS someone is looking at it"
Either way, cool demo!
[0] http://ephemeralp2p.durazo.us/ae0fad06ab58fa6bbc1599733b6c0c...
[0] http://ephemeralp2p.durazo.us/7eb67dd70747b8e979e77119e813f4...
I need to re-watch that movie.
https://www.youtube.com/watch?v=u21S_vq5CTw
That was rewarding :)
The actual way to do this an acctualy call it p2p would be with a small WebRTC framework that can bootstrap the actual site.
Would be interested to explore other ways to make pure-JS mesh networking happen. I've thought of using the JavaScript image pinging trick to "port scan" the entire subnet for peers, and communicate by "mildly DDoSing" each other with pings, but haven't actually tried yet.
Another potential method to pure-JS P2P is by using the microphone and speaker and building a mesh network at inaudible frequencies but this requires microphone permissions and won't work beyond the same room, and would be only several hundred bytes per second at best.
Good job for the innovation!