diff --git a/.gitignore b/.gitignore
index 9f11b755..3c3629e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-.idea/
+node_modules
diff --git a/LBRY.class.php b/LBRY.class.php
deleted file mode 100644
index 7fdc413a..00000000
--- a/LBRY.class.php
+++ /dev/null
@@ -1,85 +0,0 @@
- $function, 'params' => $params]));
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- $serverOutput = curl_exec($ch);
- curl_close($ch);
-
- if ($serverOutput)
- {
- $responseData = json_decode($serverOutput, true);
- if (isset($responseData['error']))
- {
- throw new Exception($responseData['error']['message'] ?? 'Something unknown went wrong');
- }
- if (isset($responseData['result']))
- {
- return $responseData['result'];
- }
- throw new Exception('Received unknown response format.');
- }
- }
-
- public static function publishPublicClaim($name, $tmpFileName)
- {
- $filePath = '/home/lbry/publishes/newupload-' . random_int(1, PHP_INT_MAX);
-
- move_uploaded_file($tmpFileName, $filePath);
-
- $apiResult = LBRY::api('publish', [
- 'name' => $name,
- 'bid' => 1,
- 'file_path' => $filePath,
- 'description' => 'An image published from spee.ch',
- 'author' => 'https://spee.ch',
- 'language' => 'en',
- 'license' => 'Public Domain',
- 'nsfw' => 0,
- 'title' => 'Image published from spee.ch'
- ]);
-
- return isset($apiResult['claim_id']);
- }
-
- public static function findTopPublicFreeClaim($name)
- {
- $claims = LBRY::api('claim_list', ['name' => $name]);
-
- if (!$claims || !isset($claims['claims']))
- {
- return null;
- }
-
- $freePublicClaims = array_filter($claims['claims'], function($claim) {
- $metadata = json_decode($claim['value'], true);
- return
- //TODO: Expand these checks AND verify it is an image claim!
- ($metadata['license'] == "Public Domain" || stripos($metadata['license'], 'Creative Commons') !== false) &&
- !isset($metadata['fee']);
- });
-
- if (count($freePublicClaims) > 1)
- {
- usort($freePublicClaims, function($claimA, $claimB) {
- if ($claimA['amount'] == $claimB['amount'])
- {
- return $claimA['height'] < $claimB['height'] ? -1 : 1;
- }
- return $claimA['amount'] > $claimB['amount'] ? -1 : 1;
- });
- }
-
- return reset($freePublicClaims);
- }
-}
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 77909b45..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017 LBRY
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
index c92edc8d..f68d744c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,44 @@
-# spee.ch
-spee.ch is a simple but powerful image hosting service on top of the LBRY protocol.
+# spee.ch (js)
+this is a clone of spee.ch with a javascript backend
-It was built in real-time on March 29th, 2017.
+## how to use this repository
+* start lbry
+ * install the [`lbry`](https://github.com/lbryio/lbry) daemon
+ * start the `lbry` daemon
+* start RabbitMQ (this will handle the queue for background processing)
+ * install & run [RabbitMQ](https://www.rabbitmq.com/#getstarted)
+* clone this repo
+* run `npm install`
+* from your terminal, run `npm start`
+ * to run hot, run `nodemon server.js`
+* start at least one worker by running `node worker.js`
+* visit [localhost:3000](http://localhost:3000) and enjoy!
-You can watch the video and learn more from [https://spee.ch](https://spee.ch)
+## site navigation
+
+* spee.ch.
+ * To publish a file, navigate to the homepage.
+* spee.ch/
';
- echo 'Received: ' . $getResult['written_bytes'] . " / " . $getResult['total_bytes'] . ' bytes';
- }
- else
- {
- echo 'There seems to be a valid claim, but are having trouble retrieving the content.';
- }
-}
-elseif (isset($_GET['new']) && $_GET['new'])
-{
- echo 'Your image is on the way. It can take a few minutes to reach the blockchain and be public. You can refresh this page to check the progress.';
-}
-else
-{
- echo 'No valid claim for this name. Make one!';
- include './publish.php';
-}
-
-exit(0);
diff --git a/index.php b/index.php
deleted file mode 100644
index 6446539d..00000000
--- a/index.php
+++ /dev/null
@@ -1,45 +0,0 @@
-Something went wrong publishing your content. We are only somewhat sorry.
spee.ch is a single-serving site that reads and publishes images to and from the LBRY blockchain.
-Examples:
-It was built live in a little over 2 hours on March 29th, 2017. You can watch the video here:
- diff --git a/package.json b/package.json new file mode 100644 index 00000000..c5793764 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "spee.ch-backend", + "version": "0.0.1", + "description": "a back end for spee.ch", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/billbitt/spee.ch-backend.git" + }, + "keywords": [ + "spee.ch", + "lbry", + "blockchain" + ], + "author": "@billbitt @vxn", + "license": "MIT", + "bugs": { + "url": "https://github.com/billbitt/spee.ch-backend/issues" + }, + "homepage": "https://github.com/billbitt/spee.ch-backend#readme", + "dependencies": { + "amqplib": "^0.5.1", + "axios": "^0.16.1", + "body-parser": "^1.17.1", + "connect-multiparty": "^2.0.0", + "express": "^4.15.2", + "nodemon": "^1.11.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..315a811f Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fourOhfour.html b/public/fourOhfour.html new file mode 100644 index 00000000..982f8678 --- /dev/null +++ b/public/fourOhfour.html @@ -0,0 +1,14 @@ + + + + + + +That page does not exist. Return home.
+ + \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 00000000..d6561367 --- /dev/null +++ b/public/index.html @@ -0,0 +1,106 @@ + + + + + + +spee.ch is a single-serving site that reads and publishes images to and from the LBRY blockchain.
+Note: these are being used for testing durring spee.ch development and may not be maintained
+There are no free, public images at that claim. You should publish one at spee.ch.
+ + \ No newline at end of file diff --git a/public/publishingClaim.html b/public/publishingClaim.html new file mode 100644 index 00000000..f599e292 --- /dev/null +++ b/public/publishingClaim.html @@ -0,0 +1,14 @@ + + + + + + +Your asset is being published by a handy background worker. You can return to spee.ch and your asset should be published to your claim shortly.
+ + \ No newline at end of file diff --git a/publish.php b/publish.php deleted file mode 100644 index c9cb46a8..00000000 --- a/publish.php +++ /dev/null @@ -1,14 +0,0 @@ - \ No newline at end of file diff --git a/routes/api-routes.js b/routes/api-routes.js new file mode 100644 index 00000000..67bbed41 --- /dev/null +++ b/routes/api-routes.js @@ -0,0 +1,29 @@ +// require dependencies +var path = require('path'); +var axios = require('axios'); +var multipart = require('connect-multiparty'); +var multipartMiddleware = multipart(); +// import helpers +var lbryApi = require('../helpers/lbryApi.js'); +var queueApi = require('../helpers/queueApi.js'); + +module.exports = function(app){ + // route to return claim list in json + app.get("/claim_list/:claim", function(req, res){ + var claim = req.params.claim; + // make a call to the daemon + axios.post('http://localhost:5279/lbryapi', { + method: "claim_list", + params: { + name: claim + } + } + ).then(function (response) { + console.log("success"); + res.send(response.data); + }).catch(function(error){ + console.log(error.data); + res.send(error.data); + }) + }); +} \ No newline at end of file diff --git a/routes/html-routes.js b/routes/html-routes.js new file mode 100644 index 00000000..2f358a86 --- /dev/null +++ b/routes/html-routes.js @@ -0,0 +1,80 @@ +// load dependencies +var path = require('path'); +var multipart = require('connect-multiparty'); +var multipartMiddleware = multipart(); +// load helpers +var lbryApi = require('../helpers/lbryApi.js'); +var queueApi = require('../helpers/queueApi.js'); + +// routes to export +module.exports = function(app){ + // route to fetch one free public claim + app.get("/favicon.ico", function(req, res){ + console.log(" >> GET request on favicon.ico"); + res.sendFile(path.join(__dirname, '../public', 'favicon.ico')); + }); + // route to publish a new claim + app.post("/publish", multipartMiddleware, function(req, res){ + // receive the request + console.log(" >> POST request on /publish"); + //console.log(">> req.files:", req.files) + console.log(" >> req.body:", req.body) + + // build the data needed to publish the file + var publishObject = { + "method":"publish", + "params": { + "name": req.body.title, + "file_path": req.files.file.path, + "bid": 0.1, + "metadata": { + "description": req.body.description, + "title": req.body.title, + "author": req.body.author, + "language": req.body.language, + "license": req.body.license, + "nsfw": req.body.nsfw.value + } + } + }; + //console.log(">> publishObject:", publishObject) + + // post the task to the que + queueApi.addNewTaskToQueue(JSON.stringify({ + type: 'publish', + data: publishObject + })); + // respond to the client that the task has been queued + res.status(200).sendFile(path.join(__dirname, '../public', 'publishingClaim.html')); + + }); + // route to fetch one free public claim + app.get("/:name/all", function(req, res){ + var name = req.params.name; + console.log(">> GET request on /" + name + " (all)"); + lbryApi.serveAllClaims(name, res); + }); + // route to fetch one free public claim + app.get("/:name/:claim_id", function(req, res){ + var uri = "lbry://" + req.params.name + "#" + req.params.claim_id; + console.log(">> GET request on /" + uri); + lbryApi.serveClaimBasedOnUri(uri, res); + }); + // route to fetch one free public claim + app.get("/:name", function(req, res){ + var name = req.params.name; + console.log(">> GET request on /" + name) + // publish a message to the cue + // queueApi.addNewTaskToQueue("return claim for " + req.params.name + " ...") + // retrieve the claim + lbryApi.serveClaimBasedOnNameOnly(name, res); + }); + // route for the home page + app.get("/", function(req, res){ + res.sendFile(path.join(__dirname, '../public', 'index.html')); + }); + // a catch-all route if someone visits a page that does not exist + app.use("*", function(req, res){ + res.sendFile(path.join(__dirname, '../public', 'fourOhfour.html')); + }); +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..7111174b --- /dev/null +++ b/server.js @@ -0,0 +1,20 @@ +// load dependencies +var express = require('express'); +var bodyParser = require('body-parser'); +var path = require('path'); +// set port +var PORT = 80; +// initialize express +var app = express(); +// make express look in the public directory for assets (css/js/img) +app.use(express.static(__dirname + '/public')); +// configure epress +app.use(bodyParser.json()); // for parsing application/json +app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded +// require in routes +require("./routes/api-routes.js")(app); +require("./routes/html-routes.js")(app); +// start server +app.listen(PORT, function() { + console.log("Listening on PORT " + PORT); +}); diff --git a/worker.js b/worker.js new file mode 100644 index 00000000..dd7b179d --- /dev/null +++ b/worker.js @@ -0,0 +1,31 @@ +// load dependencies +var amqp = require('amqplib/callback_api'); +// load helpers +var lbryApi = require('./helpers/lbryApi'); +// open a connection and a channel +amqp.connect('amqp://localhost', function(err, conn) { + // open a channel + conn.createChannel(function(err, ch) { + var q = 'task_queue2'; + // declare the cue (in case the publisher hasn't made it yet) + ch.assertQueue(q, {durable: true}); + // tell the queue to only assign one task at a time to this worker + ch.prefetch(1); + // listen for messages & pass callback for what to do with the msgs + console.log(" [x] Waiting for messages in %s. To exit press ctrl+c", q); + ch.consume(q, function(msg) { + var task = JSON.parse(msg.content.toString()); + console.log(` [o] Received a ${task.type} task`); + // initiate the task + switch(task.type) { + case 'publish': + console.log(" [-] publishing:", task.data); + lbryApi.publishClaim(task.data); + break; + default: + console.log(" [-] that task type is not recognized"); + console.log(" [x] Done"); + } + }, {noAck: true}); + }); +}); \ No newline at end of file