diff --git a/helpers/lbryApi.js b/helpers/lbryApi.js index e1ca554e..8a09f13e 100644 --- a/helpers/lbryApi.js +++ b/helpers/lbryApi.js @@ -37,7 +37,35 @@ function orderTopClaims(claimsListArray){ return claimsListArray; } +function getClaimWithUri(uri, resolve, reject){ + console.log(">> making get request to lbry daemon") + axios.post('http://localhost:5279/lbryapi', { + method: "get", + params: { uri: uri } + } + ).then(function (getUriResponse) { + console.log(">> 'get claim' success..."); + //check to make sure the daemon didn't just time out + if (getUriResponse.data.result.error === "Timeout"){ + reject("get request to lbry daemon timed out"); + } + console.log(">> response data:", getUriResponse.data); + console.log(">> dl path =", getUriResponse.data.result.download_path) + // resolve the promise with the download path for the claim we got + /* + note: put in a check to make sure we do not resolve until the download is actually complete + */ + resolve(getUriResponse.data.result.download_path); + }).catch(function(getUriError){ + console.log(">> 'get' error:", getUriError.response.data); + // reject the promise with an error message + reject(getUriError.response.data.error.message); + return; + }); +} + module.exports = { + publishClaim: function(publishObject){ axios.post('http://localhost:5279/lbryapi', publishObject) .then(function (response) { @@ -56,93 +84,81 @@ module.exports = { //res.status(500).send(JSON.stringify({msg: "your file was not published", err: error.response.data.error.message})); }) }, - serveClaimBasedOnNameOnly: function(claimName, res){ - // make a call to the daemon to get the claims list - axios.post('http://localhost:5279/lbryapi', { - method: "claim_list", - params: { - name: claimName - } - } - ).then(function (response) { - console.log(">> Claim_list success"); - console.log(">> Number of claims:", response.data.result.claims.length) - // return early if no claims were found - if (response.data.result.claims.length === 0){ - res.status(200).sendFile(path.join(__dirname, '../public', 'noClaims.html')); - return; - } - // filter the claims to return free, public claims - var freePublicClaims = filterForFreePublicClaims(response.data.result.claims); - // return early if no free, public claims were found - if (!freePublicClaims || (freePublicClaims.length === 0)){ - res.status(200).sendFile(path.join(__dirname, '../public', 'noClaims.html')); - return; - } - // order the claims - var orderedPublcClaims = orderTopClaims(freePublicClaims); - // create the uri for the first (selected) claim - console.log(">> ordered free public claims", orderedPublcClaims); - var freePublicClaimUri = "lbry://" + orderedPublcClaims[0].name + "#" + orderedPublcClaims[0].claim_id; - console.log(">> your free public claim uri:", freePublicClaimUri); - // fetch the image to display - axios.post('http://localhost:5279/lbryapi', { - method: "get", - params: { - uri: freePublicClaimUri - } - } - ).then(function (getResponse) { - console.log(">> 'get claim' success..."); - console.log(">> response data:", getResponse.data); - console.log(">> dl path =", getResponse.data.result.download_path) - // return the claim we got - res.status(200).sendFile(getResponse.data.result.download_path); - }).catch(function(getError){ - console.log(">> /c/ 'get' error:", getError.response.data); - res.status(500).send(JSON.stringify({msg: "An error occurred while fetching the free, public claim by URI.", err: getError.response.data.error.message})); + + getClaimBasedOnNameOnly: function(claimName){ + // 1. create a promise + var deferred = new Promise(function (resolve, reject){ + // 2. code to resolve or reject the promise + // make a call to the daemon to get the claims list + axios.post('http://localhost:5279/lbryapi', { // receives a promise + method: "claim_list", + params: { name: claimName } }) - }).catch(function(error){ - console.log(">> /c/ error:", error.response.data); - res.status(500).send(JSON.stringify({msg: "An error occurred while getting the claim list.", err: error.response.data.error.message})); - }) + .then(function (response) { + console.log(">> Claim_list success"); + + var claimsList = response.data.result.claims; + console.log(">> Number of claims:", claimsList.length) + + // return early if no claims were found + if (claimsList.length === 0){ + reject("no claims were found"); + console.log("exiting due to lack of claims"); + return; + } + + // filter the claims to return only free, public claims + var freePublicClaims = filterForFreePublicClaims(claimsList); + + // return early if no free, public claims were found + if (!freePublicClaims || (freePublicClaims.length === 0)){ + reject("no free, public claims were found"); + console.log("exiting due to lack of free or public claims"); + return; + } + + // order the claims + var orderedPublcClaims = orderTopClaims(freePublicClaims); + + // create the uri for the first (selected) claim + console.log(">> ordered free public claims", orderedPublcClaims); + var freePublicClaimUri = "lbry://" + orderedPublcClaims[0].name + "#" + orderedPublcClaims[0].claim_id; + console.log(">> your free public claim uri:", freePublicClaimUri); + + // fetch the image to display + getClaimWithUri(freePublicClaimUri, resolve, reject); + + }) + .catch(function(error){ + console.log(">> error:", error); + // reject the promise with an approriate message + reject(error.response.data.error); + return; + }); + }); + // 3. return the promise + return deferred; + }, - serveClaimBasedOnUri: function(uri, res){ + + getClaimBasedOnUri: function(uri){ /* to do: need to pass the URI through a test (use 'resolve') to see if it is free and public. Right now it is jumping straight to 'get'ing and serving the asset. */ - console.log(">> your uri:", uri); - // fetch the image to display - axios.post('http://localhost:5279/lbryapi', { // to do: abstract this code to a function that can be shared - method: "get", - params: { - uri: uri - } - } - ).then(function (getResponse) { - console.log(">> 'get claim' success..."); - console.log(">> response data:", getResponse.data); - console.log(">> dl path =", getResponse.data.result.download_path) - /* - to do: make sure the file has completed downloading before serving back the file - */ - // return the claim we got - res.status(200).sendFile(getResponse.data.result.download_path); + var deferred = new Promise(function (resolve, reject){ + console.log(">> your uri:", uri); + // fetch the image to display + getClaimWithUri(uri, resolve, reject); + }); + return deferred; - /* delete the file after a certain amount of time? */ - - }).catch(function(error){ - console.log(">> /c/ 'get' error:", error.response.data); - res.status(500).send(JSON.stringify({msg: "an error occurred", err: error.response.data.error.message})); - }) }, - serveAllClaims: function(claimName, res){ + + serveAllClaims: function(claimName, res){ // note: work in progress // make a call to the daemon to get the claims list axios.post('http://localhost:5279/lbryapi', { method: "claim_list", - params: { - name: claimName - } + params: { name: claimName } } ).then(function (response) { console.log(">> Claim_list success"); @@ -163,7 +179,10 @@ module.exports = { // order the claims var orderedPublicClaims = orderTopClaims(freePublicClaims); // serve the response - res.status(200).send(orderedPublicClaims); //to do: rather than returning json, serve a page of all these claims + /* + to do: rather than returning json, serve a page of all these claims + */ + res.status(200).send(orderedPublicClaims); }).catch(function(error){ console.log(">> /c/ error:", error.response.data); // serve the response diff --git a/package.json b/package.json index c5793764..38ad5ab0 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "body-parser": "^1.17.1", "connect-multiparty": "^2.0.0", "express": "^4.15.2", - "nodemon": "^1.11.0" + "nodemon": "^1.11.0", + "socket.io": "^2.0.1" } } diff --git a/public/claim.html b/public/claim.html new file mode 100644 index 00000000..129b7fa4 --- /dev/null +++ b/public/claim.html @@ -0,0 +1,36 @@ + + + + + + + Spee.ch Claim + + +
+

spee.ch

+

spee.ch is a single-serving site that reads and publishes images to and from the LBRY blockchain.

+

Status:

+

Your image is being retrieved

+
+ + + + \ No newline at end of file diff --git a/public/eagle.jpg b/public/eagle.jpg new file mode 100644 index 00000000..cb736738 Binary files /dev/null and b/public/eagle.jpg differ diff --git a/public/index.html b/public/index.html index d6561367..d5af3d08 100644 --- a/public/index.html +++ b/public/index.html @@ -23,9 +23,11 @@
Image preview...
+ Name: +
Title:
- Description: + Description:
Author:
@@ -36,9 +38,9 @@
- NSFW: + -
@@ -101,6 +103,9 @@ previewFile(); //calls the function named previewFile() - + + \ No newline at end of file diff --git a/routes/html-routes.js b/routes/html-routes.js index 2f358a86..3f32294f 100644 --- a/routes/html-routes.js +++ b/routes/html-routes.js @@ -6,6 +6,27 @@ var multipartMiddleware = multipart(); var lbryApi = require('../helpers/lbryApi.js'); var queueApi = require('../helpers/queueApi.js'); +// helper functions +function createPublishObject(req){ + var publishObject = { + "method":"publish", + "params": { + "name": req.body.name, + "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 + } + } + }; + return publishObject; +} + // routes to export module.exports = function(app){ // route to fetch one free public claim @@ -15,30 +36,10 @@ module.exports = function(app){ }); // 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) - + var publishObject = createPublishObject(req); + console.log("publish", publishObject); // post the task to the que queueApi.addNewTaskToQueue(JSON.stringify({ type: 'publish', @@ -46,7 +47,6 @@ module.exports = function(app){ })); // 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){ @@ -56,23 +56,21 @@ module.exports = function(app){ }); // 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); + console.log(">> GET request on /" + req.params.name + "#" + req.params.claim_id); + res.status(200).sendFile(path.join(__dirname, '../public', 'claim.html')); }); // 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); + // send page (includes a socket to get the file) + res.status(200).sendFile(path.join(__dirname, '../public', 'claim.html')); }); // 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')); diff --git a/routes/sockets-routes.js b/routes/sockets-routes.js new file mode 100644 index 00000000..51bbbb0a --- /dev/null +++ b/routes/sockets-routes.js @@ -0,0 +1,57 @@ +module.exports = function(app) { + var http = require('http').Server(app); + var io = require('socket.io')(http); + var fs = require('fs'); + var path = require('path'); + var lbryApi = require('../helpers/lbryApi.js'); + + function sendTheImage(socket, filePath){ + fs.readFile(filePath, function(err, buff){ + if (err) { + console.log("socket: fs err:", err); + return; + }; + //console.log("buff", buff); + socket.emit('claim-send', { image: true, buffer: buff.toString('base64') }); + console.log('socket: the image file has been sent via sockets'); + }); + } + + io.on('connection', function(socket){ + console.log('a user connected'); + + // serve an image file from the server + socket.on('claim-request', function(query){ + // 1. retrieve the image from lbry via daemon + console.log("socket: received claim request for:", query) + if (query.indexOf("/") === -1){ + var promise = lbryApi.getClaimBasedOnNameOnly(query) + } else { + var uri = query.replace("/", "#"); + var promise = lbryApi.getClaimBasedOnUri(uri) + } + promise.then(function(data){ + console.log("socket: claim-request - success:", data) + // 3. serve the image back once it is retrieved + sendTheImage(socket, data); + return; + }) + .catch(function(error){ + console.log("socket: claim-request - error:", error) + // handle the error + socket.emit("claim-update", error); + return; + }); + + // 2. emit updates as the image is being retrieved + socket.emit("claim-update", "We are getting your claim for " + query); + }) + + // handle disconnect + socket.on('disconnect', function(){ + console.log('user disconnected'); + }); + }); + + return http; +} \ No newline at end of file diff --git a/server.js b/server.js index b812f4cb..5872b342 100644 --- a/server.js +++ b/server.js @@ -2,19 +2,29 @@ var express = require('express'); var bodyParser = require('body-parser'); var path = require('path'); + // set port var PORT = 3000; -// initialize express + +// initialize express app var app = express(); + // make express look in the public directory for assets (css/js/img) app.use(express.static(__dirname + '/public')); -// configure epress + +// configure express app 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 express routes require("./routes/api-routes.js")(app); require("./routes/html-routes.js")(app); + +// include socket.io functionality +// this wraps the server in sockets, to intercept incoming sockets requests +var http = require("./routes/sockets-routes.js")(app); + // start server -app.listen(PORT, function() { +http.listen(PORT, function() { console.log("Listening on PORT " + PORT); });