From 3a3661feec6832ada5e982ae619fb725933ce135 Mon Sep 17 00:00:00 2001 From: "Hee Kyoung, Oh" Date: Sat, 17 Dec 2016 18:10:23 +0900 Subject: [PATCH] [TIC-UI] add the filedownload feature - add the filedownload button - add the file stats (size and update time) - add the router - changing the file name ws.filesystem.js to filesystem.js - changing the file name ws.mic.js to mic.js Change-Id: Id793c91c626a4f27cb0c763ecfad04a2851d63e8 Signed-off-by: Hee Kyoung, Oh --- app.js | 34 +++++--- public/src/css/style.css | 39 +++++++++ public/src/index.html | 31 ++++++- public/src/js/page/image.js | 204 +++++++++++++++++++++++++++++++++++++++----- server/fs/filesystem.js | 58 +++++++++++++ server/fs/mic.js | 56 ++++++++++++ server/fs/ws.filesystem.js | 7 +- server/routes/router.js | 37 ++++++++ 8 files changed, 431 insertions(+), 35 deletions(-) create mode 100644 server/fs/filesystem.js create mode 100644 server/fs/mic.js create mode 100644 server/routes/router.js diff --git a/app.js b/app.js index 15ba9a5..4477913 100644 --- a/app.js +++ b/app.js @@ -6,7 +6,9 @@ var fs = require('fs'); var express = require('express'); var bodyParser = require('body-parser'); -var FileSystem = require('./server/fs/ws.filesystem'); +var FileSystem = require('./server/fs/filesystem'); +var Mic = require('./server/fs/mic'); +var Router = require('./server/routes/router'); var app = express(); var server = http.createServer(app); @@ -20,15 +22,7 @@ app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(express.static(path.join(__dirname, '/public/src'))); //module directory - -/** - * TODO - * - * apply router - * - * var AppRouter = require('./routes'); - * app.use(mount('/', AppRouter)); - */ +app.use('/api', Router); server.listen(app.get('port'), process.env.IP || "0.0.0.0", function () { var addr = server.address(); @@ -60,6 +54,26 @@ io.on('connection', function (socket) { socket.emit('ws/fs/image/list/to', msgData); }); + socket.on('ws/fs/image/add/from', function (data) { + console.log(data); + var msgData, ans; + + msgData = {}; + + function sendMsg(msg) { + // send + socket.emit('ws/fs/image/add/to', msg); + } + + // get the list of file + Mic.create(data, socket); + }); + + socket.on('ws/fs/image/download/from', function (data) { + console.log(data); + + }); + socket.on('disconnect', function () { console.log('socket disconnect'); }); diff --git a/public/src/css/style.css b/public/src/css/style.css index 04af47a..0739b02 100644 --- a/public/src/css/style.css +++ b/public/src/css/style.css @@ -141,6 +141,45 @@ html { position: relative; overflow: auto; } +#tic-image-list { + margin-top: 3px; +} + +.image-list-time { + padding-left: 10px; +} + +.image-item { + overflow: hidden; + text-overflow: ellipsis; +} + +.infobox { + padding: 20px; + margin: 20px 0; + border: 1px solid #eee; + border-radius: 3px; + margin-top: 3px; + height: 25vh; + overflow: auto; + font-size: 14px; +} + +.infoboxheader { + padding-left: 15px; + border: 1px solid #eee; + border-left-width: 5px; + border-radius: 3px; + margin-top: -5px; + height: 5vh; + overflow: hidden; + text-overflow: ellipsis; + border-left-color: #1b809e; +} +.infoboxheader h4 { + color: #1b809e; +} + @media (min-width: 992px) { #tic-image-summary { height: 70vh; diff --git a/public/src/index.html b/public/src/index.html index e05f700..2583932 100644 --- a/public/src/index.html +++ b/public/src/index.html @@ -181,13 +181,40 @@
Image List
-

Image list and download

-
+
+

create a image

+
+
+
+
+
+
+

image list

+
+
    + + diff --git a/public/src/js/page/image.js b/public/src/js/page/image.js index 485c1ce..77c3136 100644 --- a/public/src/js/page/image.js +++ b/public/src/js/page/image.js @@ -7,22 +7,28 @@ define([ ) { 'use strict'; - var client; + // connected socket object + var client, + + // the list of checked pakages + checkedPackagesList, + + // template for the URL + URL_EXPORTS = '<%= protocol %>//<%= hostname %>:<%= port %>/exports', + + // the path for ks + PATH_TIC_KS = '/tmp/tic/ks/', + + // the path for images + PATH_TIC_IMAGES = '/tmp/tic/images/'; + + function updateList(socket) { - /** - * FIXME - * - * changed to be set the path dynamically - */ var msgData = { - path: './resource/images/' + path: PATH_TIC_IMAGES }; - /** - * TODO - * checks - */ client = socket; client.emit('ws/fs/image/list/from', msgData); @@ -33,11 +39,39 @@ define([ list = data.list; tableDomElem = $('#tic-image-list'); - /** - * FIXME - */ list.forEach(function (file) { - tableDomElem.append(file.name + ' (size:' + file.size + ')' + '
    '); + /** + * @info + * + * file = { + * name: '', + * size: '' + * } + */ + var liElem, aElem, spanElem, fileName, hrefPath; + + fileName = file.name; + + hrefPath = '/api/fs/download/' + fileName; + + liElem = document.createElement('li'); + liElem.innerText = fileName; + liElem.setAttribute('class', 'list-group-item image-item'); + + spanElem = document.createElement('span'); + spanElem.innerText = '(' + file.size + 'B / ' + file.mtime + ')'; + spanElem.setAttribute('class', 'image-list-time'); + + aElem = document.createElement('a'); + aElem.innerText = 'Download'; + aElem.setAttribute('class', 'badge'); + aElem.setAttribute('href', hrefPath); + aElem.setAttribute('data-name', fileName); + aElem.setAttribute('download', 'download'); + + liElem.appendChild(spanElem); + liElem.appendChild(aElem); + tableDomElem.append(liElem); }); }); @@ -49,12 +83,12 @@ define([ var packageCount = $('#tic-image-package-count').empty(); var packageList = $('#tic-image-package-list').empty(); - var list = require('js/page/package').getCheckedPackages(); - var count = _.size(list); - var imageSize = _.sumBy(list, function getImageSize(item) { + checkedPackagesList = require('js/page/package').getCheckedPackages(); + var count = _.size(checkedPackagesList); + var imageSize = _.sumBy(checkedPackagesList, function getImageSize(item) { return _.toNumber(item.size); }); - var imageInstalledSize = _.sumBy(list, function getImageInstalled(item) { + var imageInstalledSize = _.sumBy(checkedPackagesList, function getImageInstalled(item) { return _.toNumber(item.installed); }); @@ -67,16 +101,137 @@ define([ if (_.isNumber(count)) { packageCount.html(count); } - if (!_.isEmpty(list)) { - packageList.html(_.orderBy(_.map(list, 'text')).join('
    ')); + if (!_.isEmpty(checkedPackagesList)) { + packageList.html(_.orderBy(_.map(checkedPackagesList, 'text')).join('
    ')); } $('#tic-image-create').prop('disabled', count === 0); } + function confirmCreateImage() { + var isOk; + + $('#tic-image-create').prop('disabled', true); + + // when packages are checked nothing + if (_.isEmpty(checkedPackagesList)) { + $('#tic-image-create').prop('disabled', true); + return; + } + + function createImage(pathKsFile) { + /** + * TODO - checks the msgData + */ + var msgData, tableDomElem; + msgData = { + pathKsFile: pathKsFile, + pathOutput: PATH_TIC_IMAGES + }; + + tableDomElem = $('#tic-image-new-log'); + + client.emit('ws/fs/image/add/from', msgData); + + client.on('ws/fs/image/add/to', function (data) { + console.log(data); + var elem = document.createElement('p'); + elem.innerText = data; + tableDomElem.append(elem); + }); + + // when finished + client.on('ws/fs/image/add/finished', function (data) { + $('#tic-image-create').prop('disabled', false); + $('#tic-image-new').empty(); + updateList(); + }); + } + + function getExportsUrl() { + return _.template(URL_EXPORTS)({ + protocol: location.protocol, + hostname: location.hostname, + port: parseInt(location.port) + 1 + }); + } + + function getKickstartRecipeFile() { + return new Promise(function (resolve, reject) { + var msgData = { + recipe: { + name: 'default' + }, + packages: _.map(checkedPackagesList, 'name'), + output: PATH_TIC_KS + }; + + console.log('url = ' + getExportsUrl()); + console.log(msgData); + + $.ajax({ + type: 'POST', + contentType: 'text/plain', + data: JSON.stringify(msgData), + dataType: 'json', + url: getExportsUrl(), + success: function (res) { + console.log(res); + resolve(res.data); + }, + error: function (err) { + reject(err.responseText); + } + }); + }); + } + + /** + * FIXME + * using modal + * + * $('#confirmModalCreateImage').modal('show'); + */ + // confirm + isOk = window.confirm('Are you sure?'); + if (isOk) { + getKickstartRecipeFile() + .then(createImage) + .catch(function (err) { + console.log(err); + Util.showLoadingDialog(false); + Util.showAlertDialog('Failed to create a image.
    Please check the ks file.'); + }); + } else { + $('#tic-image-create').prop('disabled', false); + } + } + + /** + * Initiation for the all widgets + */ + function _initWidgets() { + // button + $('#tic-image-create').prop('disabled', true); + $('#tic-image-create').click(confirmCreateImage); + + /** + * FIXME + * chanage 'confirm' to 'modal' + * + * modal + * $('#confirmModalCreateImage').modal({ + * keyboard: false, + * backdrop: true + * }); + */ + + } + function init() { console.log('image: init'); - $('#tic-image-create').prop('disabled', true); + + _initWidgets(); } init(); @@ -87,6 +242,11 @@ define([ * @method updateSummary */ updateSummary: updateSummary, + + /** + * Update list in image page + * @method updateList + */ updateList: updateList } diff --git a/server/fs/filesystem.js b/server/fs/filesystem.js new file mode 100644 index 0000000..68cbf9e --- /dev/null +++ b/server/fs/filesystem.js @@ -0,0 +1,58 @@ +'use strict'; +/** + * using websocket + */ + +var fs = require('fs'); +var path = require('path'); + +var FileSystem = {}; + +FileSystem.list = function (dirPath) { + console.log('filesystem.list called'); + var results, info, list; + + results = []; + + if(!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + } + + list = fs.readdirSync(dirPath); + list.forEach(function(file) { + var fileStat, filePath; + + filePath = dirPath + file; + + fileStat = fs.statSync(filePath); + + if (fileStat && fileStat.isDirectory()) { + results = results.concat(FileSystem.list(filePath)) + } else { + /** + * TODO + * to be extended .. + */ + info = { + name: file, + size: fileStat['size'], + atime: fileStat['atime'], + mtime: fileStat['mtime'], + ctime: fileStat['ctime'], + birthtime: fileStat['birthtime'] + } + results.push(info); + } + }); + return results; +}; + +FileSystem.remove = function () { + console.log('filesystem.remove called'); +}; + +FileSystem.download = function () { + console.log('filesystem.download called'); +}; + +module.exports = FileSystem; \ No newline at end of file diff --git a/server/fs/mic.js b/server/fs/mic.js new file mode 100644 index 0000000..b95e0fa --- /dev/null +++ b/server/fs/mic.js @@ -0,0 +1,56 @@ +'use strict'; +/** + * using websocket + */ + +var fs = require('fs'); +var path = require('path'); +var exec = require('child_process').exec; +var util = require('util'); + +var Mic = {}; + +Mic.subprocess = function (processname, arg, cb) { + var p = exec(processname, arg); + p.on('exit', cb.exit); + p.stdout.on('data', cb.stdout || function (out) { + process.stdout.write(out); + }); + p.stderr.on('data', cb.stderr || function (err) { + process.stdout.write(err); + }); +}; + +Mic.create = function (paramObj, client) { + console.log('Mic.create called'); + var micProcess, micProcessArgs, mic, child, stdoutPath, exitPath; + + stdoutPath = 'ws/fs/image/add/to'; + exitPath = 'ws/fs/image/add/finished'; + + micProcess = 'sudo mic cr loop ' + paramObj.pathKsFile; + micProcessArgs = []; + micProcessArgs.push(util.format('-A %s', 'x86_64')); + micProcessArgs.push(util.format('-o %s', paramObj.pathOutput)); + + function sendMsg(path, msg) { + client.emit(path, msg); + } + + Mic.subprocess(micProcess, micProcessArgs, { + stdout: function (out) { + console.log('stdout' + out); + sendMsg(stdoutPath, 'stdout: ' + out); + }, + stderr: function (out) { + console.log('stderr' + out); + sendMsg(stdoutPath, 'stderr: ' + out); + }, + exit: function (out) { + console.log('exit: ' + out); + sendMsg(exitPath, 'exit: ' + out); + } + }); +}; + +module.exports = Mic; \ No newline at end of file diff --git a/server/fs/ws.filesystem.js b/server/fs/ws.filesystem.js index 736f115..f4d79f6 100644 --- a/server/fs/ws.filesystem.js +++ b/server/fs/ws.filesystem.js @@ -6,10 +6,15 @@ var path = require('path'); var FileSystem = {}; FileSystem.list = function (dirPath) { + console.log('FileSystem.list called'); var results, info, list; results = []; + if(!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + } + list = fs.readdirSync(dirPath); list.forEach(function(file) { var fileStat, filePath; @@ -26,7 +31,7 @@ FileSystem.list = function (dirPath) { * to be extended .. */ info = { - name: filePath, + name: file, size: fileStat['size'] } results.push(info); diff --git a/server/routes/router.js b/server/routes/router.js new file mode 100644 index 0000000..a276618 --- /dev/null +++ b/server/routes/router.js @@ -0,0 +1,37 @@ +var express = require('express'); +var router = express.Router(); +var mime = require('mime'); +var fs = require('fs'); +var path = require('path'); + +router.use(function timeLog(req, res, next) { + var time = new Date(); + console.log('Time: ', time.toISOString()); + next(); +}); + +/** + * API + * + * path : /api/fs/download + * request body : { + * filename: 'filename.ks' + * } + */ +router.get('/fs/download/:filename', function (req, res) { + var fileName, filePath, fileOptions, fileMimetype, fileStream; + console.log('>> file download called'); + + fileName = req.params.filename; + filePath = '/tmp/tic/images/' + fileName; + fileMimetype = mime.lookup(filePath); + console.log('>> filename: ' + req.params.filename + ', mime: ' + fileMimetype); + + res.setHeader('Content-disposition', 'attachment; filename=' + fileName); + res.setHeader('Content-type', fileMimetype); + + fileStream = fs.createReadStream(filePath); + fileStream.pipe(res); +}); + +module.exports = router; \ No newline at end of file -- 2.7.4