Merge "fix packaging script"
diff --git a/gui/chronosharegui.cpp b/gui/chronosharegui.cpp
index 898f6c4..cdc5dc0 100644
--- a/gui/chronosharegui.cpp
+++ b/gui/chronosharegui.cpp
@@ -355,7 +355,13 @@
void ChronoShareGui::openInWebBrowser()
{
- QDesktopServices::openUrl(QUrl("http://localhost:9001"));
+ QUrl url ("http://localhost:9001/");
+ url.setFragment ("fileList&"
+ "user=" + QUrl::toPercentEncoding (m_username) + "&"
+ "folder=" + QUrl::toPercentEncoding (m_sharedFolderName));
+
+ // i give up. there is double encoding and I have no idea how to fight it...
+ QDesktopServices::openUrl (url);
}
void ChronoShareGui::openFile()
diff --git a/gui/html/chronoshare.js b/gui/html/chronoshare.js
index c8b8ae0..d94bb5f 100644
--- a/gui/html/chronoshare.js
+++ b/gui/html/chronoshare.js
@@ -1,5 +1,104 @@
+var CHRONOSHARE;
+
+var PAGE = "folderHistory";
+var PARAMS = [ ];
+var URIPARAMS = "";
+
+function nav_anchor (aurl) {
+ aurl = aurl.split('#');
+ if (aurl[1])
+ {
+ aurl_split = aurl[1].split ('&');
+ page = aurl_split[0];
+
+ vars = [ ];
+ for (var i = 1; i < aurl_split.length; i++)
+ {
+ hash = aurl_split[i].split('=');
+ vars.push(hash[0]);
+ // there is strange double-encoding problem...
+ vars[hash[0]] = decodeURIComponent (decodeURIComponent (hash[1]));
+ }
+
+ if (page != PAGE)
+ {
+ PAGE = page;
+ PARAMS = vars;
+ URIPARAMS = aurl[1];
+
+ if (CHRONOSHARE) {
+ CHRONOSHARE.run ();
+ }
+ }
+ else if (aurl != URIPARAMS)
+ {
+ PARAMS = vars;
+ URIPARAMS = aurl[1];
+
+ if (CHRONOSHARE) {
+ CHRONOSHARE.run ();
+ }
+ }
+ }
+}
+
+$(document).ready (function () {
+ nav_anchor (window.location.href);
+
+ if (!PARAMS.user || !PARAMS.folder)
+ {
+ $("#error").html ("user and folder must be be specified in the URL");
+ $("#error").removeClass ("hidden");
+ return;
+ }
+ else {
+ // update in-page URLs
+ $(".needs-get-url").each (function (index,element) {
+ this.href += "&user="+encodeURIComponent (encodeURIComponent (PARAMS.user))
+ + "&folder="+encodeURIComponent (encodeURIComponent (PARAMS.folder));
+ });
+ $(".needs-get-url").removeClass ("needs-get-url");
+ }
+
+ CHRONOSHARE = new ChronoShare (PARAMS.user, PARAMS.folder);
+ CHRONOSHARE.run ();
+
+ $("a").click (function () {
+ nav_anchor (this.href)
+ });
+
+ $(window).on('hashchange', function() {
+ nav_anchor (window.location.href);
+ });
+});
+
+/**
+ * @brief Convert binary data represented as non-escaped hex string to Uint8Array
+ * @param str String like ba0cb43e4b9639c114a0487d5faa7c70452533963fc8beb37d1b67c09a48a21d
+ *
+ * Note that if string length is odd, null will be returned
+ */
+StringHashToUint8Array = function (str) {
+ if (str.length % 2 != 0) {
+ return null;
+ }
+
+ var buf = new Uint8Array (str.length / 2);
+
+ for (var i = 0; i < str.length; i+=2) {
+ value = parseInt (str.substring (i, i+2), 16);
+ buf[i/2] = value;
+ }
+
+ return buf;
+};
+
$.Class ("FilesClosure", {}, {
+ init: function (chronoshare) {
+ this.chronoshare = chronoshare;
+ },
+
upcall: function(kind, upcallInfo) {
$("#loader").fadeOut (500); // ("hidden");
if (kind == Closure.UPCALL_CONTENT) {
@@ -9,21 +108,56 @@
data = JSON.parse (convertedData);
// error handling?
- // if (data.files instanceof Array) {
- // alert (data.files);
- // }
+ table = $("#content").append (
+ $("<table />", { "class": "item-list" })
+ .append ($("<thead />")
+ .append ($("<tr />")
+ .append ($("<th />", { "class": "filename border-left", "scope": "col" }).text ("Filename"))
+ .append ($("<th />", { "class": "version", "scope": "col" }).text ("Version"))
+ .append ($("<th />", { "class": "modified", "scope": "col" }).text ("Modified"))
+ .append ($("<th />", { "class": "modified-by border-right", "scope": "col" }).text ("Modified By"))))
+ .append ($("<tbody />", { "id": "file-list-files" }))
+ .append ($("<tfoot />")
+ .append ($("<tr />")
+ .append ($("<td />", { "colspan": "4", "class": "border-right border-left" })))));
- var html = $("tbody#files");
+ var html = $("#file-list-files");
for (var i = 0; i < data.files.length; i++) {
file = data.files[i];
- html = html.append ([
- "<tr"+(i%2?" class=\"odd\"":"")+">",
- "<td class=\"border-left\">" + file.filename + "</td>",
- "<td>" + file.version + "</td>",
- "<td>" + file.timestamp + "</td>",
- "<td class=\"border-right\">" + "</td>",
- "</tr>"
- ].join());
+
+ row = $("<tr />");
+ if (i%2) { row.addClass ("odd"); }
+
+ row.bind('mouseenter mouseleave', function() {
+ $(this).toggleClass('highlighted');
+ });
+
+ // fileHistoryUrl = new Name ()
+ // .add (this.chronoshare.actions)
+ // .add (file.filename)
+ // .add ("nonce")
+ // .addSegment (0);
+ // row.attr ("history", fileHistoryUrl.to_uri ());
+ row.bind('click', function () {
+ url = "#fileHistory";
+ url += "&item=" + encodeURIComponent(encodeURIComponent(file.filename));
+ pos = URIPARAMS.indexOf ("&");
+ if (pos >= 0) {
+ url += URIPARAMS.substring (pos)
+ }
+
+ document.location = url;
+ nav_anchor (document.location.href);
+ });
+
+ row.append ($("<td />", {"class": "border-left"}).text (file.filename));
+ row.append ($("<td />").text (file.version));
+ row.append ($("<td />").text (new Date (file.timestamp)));
+ row.append ($("<td />")
+ .append ($("<userName />").text (file.owner.userName))
+ .append ($("<seqNo> /").text (file.owner.seqNo)));
+
+ html = html.append (row);
}
}
else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
@@ -33,7 +167,76 @@
else {
$("#error").html ("Unknown error happened");
$("#error").removeClass ("hidden");
- // some kind of error
+ }
+ }
+});
+
+
+$.Class ("HistoryClosure", {}, {
+ init: function (chronoshare) {
+ this.chronoshare = chronoshare;
+ },
+
+ upcall: function(kind, upcallInfo) {
+ $("#loader").fadeOut (500); // ("hidden");
+ if (kind == Closure.UPCALL_CONTENT) {
+ convertedData = DataUtils.toString (upcallInfo.contentObject.content);
+ $("#json").text (convertedData);
+ $("#json").removeClass ("hidden");
+ data = JSON.parse (convertedData);
+
+ // error handling?
+ table = $("#content").append (
+ $("<table />", { "class": "item-list" })
+ .append ($("<thead />")
+ .append ($("<tr />")
+ .append ($("<th />", { "class": "filename border-left", "scope": "col" }).text ("Filename"))
+ .append ($("<th />", { "class": "version", "scope": "col" }).text ("Version"))
+ .append ($("<th />", { "class": "modified", "scope": "col" }).text ("Modified"))
+ .append ($("<th />", { "class": "modified-by border-right", "scope": "col" }).text ("Modified By"))))
+ .append ($("<tbody />", { "id": "history-list-actions" }))
+ .append ($("<tfoot />")
+ .append ($("<tr />")
+ .append ($("<td />", { "colspan": "4", "class": "border-right border-left" })))));
+
+ var html = $("#history-list-actions");
+ for (var i = 0; i < data.actions.length; i++) {
+ action = data.actions[i];
+
+ row = $("<tr />");
+ if (i%2) { row.addClass ("odd"); }
+
+ row.bind('mouseenter mouseleave', function() {
+ $(this).toggleClass('highlighted');
+ });
+
+ fileHistoryUrl = new Name ()
+ .add (this.chronoshare.actions)
+ .add (action.filename)
+ .add ("nonce")
+ .addSegment (0);
+ // row.attr ("history", fileHistoryUrl.to_uri ());
+ row.bind('click', function () {
+ // alert (fileHistoryUrl.to_uri ());
+ });
+
+ row.append ($("<td />", {"class": "border-left"}).text (action.filename));
+ row.append ($("<td />").text (action.version));
+ row.append ($("<td />").text (new Date (action.timestamp)));
+ row.append ($("<td />")
+ .append ($("<userName />").text (action.id.userName))
+ .append ($("<seqNo> /").text (action.id.seqNo)));
+
+ html = html.append (row);
+ }
+ }
+ else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+ $("#error").html ("Interest timed out");
+ $("#error").removeClass ("hidden");
+ }
+ else {
+ $("#error").html ("Unknown error happened");
+ $("#error").removeClass ("hidden");
}
}
});
@@ -49,113 +252,38 @@
this.restore = new Name ("/localhost").add (this.username).add ("chronoshare").add (foldername).add ("cmd").add ("restore").add ("file");
- this.ndn = new NDN ({host:"127.0.0.1", getHostAndPort: function() { return {host: "127.0.0.1", port: 9696}}});
- // this.ndn.transport.connect (this.ndn);
+ // this.ndn = new NDN ({host:"127.0.0.1", getHostAndPort: function() { return {host: "127.0.0.1", port: 9696}}});
+ this.ndn = new NDN ({host:"127.0.0.1"});
},
- run: function () {
- request = new Name ().add (this.files)./*add (folder_in_question).*/add ("nonce").addSegment (0);
- console.log (request.to_uri ());
- $("#files").empty ();
- // $("#loader").removeClass ("hidden");
- $("#loader").fadeIn (500);
- this.ndn.expressInterest (request, new FilesClosure ());
- }
-// ,
- // sendRequest: function () {
- // alert ('bla');
- // }
+ run: function () {
+ $("#content").empty ();
+ $("#loader").fadeIn (500);
+ $("#error").addClass ("hidden");
+
+ if (PAGE == "fileList") {
+ request = new Name ().add (this.files)./*add (folder_in_question).*/add ("nonce").addSegment (0);
+ console.log (request.to_uri ());
+ this.ndn.expressInterest (request, new FilesClosure (this));
+ }
+ else if (PAGE == "folderHistory") {
+ request = new Name ().add (this.actions)./*add (folder_in_question).*/add ("nonce").addSegment (0);
+ console.log (request.to_uri ());
+ this.ndn.expressInterest (request, new HistoryClosure (this));
+ }
+ else if (PAGE == "fileHistory") {
+ if (!PARAMS.item) {
+ $("#loader").fadeOut (500); // ("hidden");
+ $("#error").html ("incorrect input for fileHistory command");
+ $("#error").removeClass ("hidden");
+ return;
+ }
+ request = new Name ().add (this.actions).add (PARAMS.item).add ("nonce").addSegment (0);
+ console.log (request.to_uri ());
+ this.ndn.expressInterest (request, new HistoryClosure (this));
+ }
+ }
});
-// $.Class ("onFiles",
-// {
-// },
-
-// {
-// upcall: function(kind, upcallInfo, tmp) {
-// if (kind
-// }
-// });
-
-// var AsyncGetClosure = function AsyncGetClosure() {
-// Closure.call(this);
-// };
-
-// AsyncGetClosure.prototype.upcall = function(kind, upcallInfo, tmp) {
-// if (kind == Closure.UPCALL_FINAL) {
-// // Do nothing.
-// } else if (kind == Closure.UPCALL_CONTENT) {
-// var content = upcallInfo.contentObject;
-// var nameStr = content.name.getName().split("/").slice(5,6);
-
-// if (nameStr == "prefix") {
-// document.getElementById('prefixcontent').innerHTML = DataUtils.toString(content.content);
-// prefix();
-// } else if (nameStr == "link") {
-// document.getElementById('linkcontent').innerHTML = DataUtils.toString(content.content);
-// link();
-// } else {
-// var data = DataUtils.toString(content.content);
-// var obj = jQuery.parseJSON(data);
-// document.getElementById("lastupdated").innerHTML = obj.lastupdated;
-// document.getElementById("lastlog").innerHTML = obj.lastlog;
-// document.getElementById("lasttimestamp").innerHTML = obj.lasttimestamp;
-// }
-// } else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
-// console.log("Closure.upcall called with interest time out.");
-// }
-// return Closure.RESULT_OK;
-// };
-
-// function getStatus(name) {
-// // Template interest to get the latest content.
-// var interest = new Interest("/tmp/");
-// interest.childSelector = 1;
-// interest.interestLifetime = 4000;
-
-// ndn.expressInterest(new Name("/ndn/memphis.edu/netlab/status/" + name), new AsyncGetClosure(), interest);
-// }
-
-// // Calls to get the content data.
-// function begin() {
-// getStatus("metadata");
-// getStatus("prefix");
-// getStatus("link");
-// }
-
-// var ndn;
-// $(document).ready(function() {
-// $("#all").fadeIn(500);
-// var res = detect();
-
-// if (!res) {
-// $("#base").fadeOut(50);
-// $("#nosupport").fadeIn(500);
-// } else {
-// //$("#all").fadeIn(500);
-
-// $.get("test.php", function() {
-// openHandle = function() { begin() };
-// ndn = new NDN({host:hostip, onopen:openHandle});
-// ndn.transport.connectWebSocket(ndn);
-// $("#base").fadeOut(500, function () {
-// $("#status").fadeIn(1000);
-// });
-// });
-// }
-// });
-
-// $("#continue").click(function() {
-// $("#nosupport").fadeOut(50);
-// $("#base").fadeIn(500);
-// $.get("test.php", function() {
-// openHandle = function() { begin() };
-// ndn = new NDN({host:hostip, onopen:openHandle});
-// ndn.transport.connectWebSocket(ndn);
-// $("#base").fadeOut(500, function () {
-// $("#status").fadeIn(1000);
-// });
-// });
-// });
diff --git a/gui/html/index.html b/gui/html/index.html
index 21842a8..0b21c61 100644
--- a/gui/html/index.html
+++ b/gui/html/index.html
@@ -22,8 +22,8 @@
<nav>
<ul>
- <li><a href="#files">File list</a></li>
- <li><a href="#history">History</a></li>
+ <li><a class="needs-get-url" href="#fileList">File list</a></li>
+ <li><a class="needs-get-url" href="#folderHistory">Folder history</a></li>
</ul>
</nav>
</header>
@@ -31,35 +31,18 @@
<article>
<!-- <img id="loader" src="load.gif" /> -->
<div id="content" class="hidden">
-
- <table class="file-list">
- <thead>
- <tr>
- <th class="filename border-left" scope="col">Filename</th>
- <th class="version" scope="col">Version</th>
- <th class="modified" scope="col">Modified</th>
- <th class="modified-by border-right" scope="col">Modified By</th>
- </tr>
- </thead>
-
- <tbody id="files">
- </tbody>
-
- <tfoot><tr><td colspan="4" class="border-right border-left"></td></tr></tfoot>
- </table>
-
- <div class="hidden" id="loader">
- <img src="load.gif" />
- </div>
-
-
- <red class="hidden" id="error">
- </red>
-
- <pre class="hidden" id="json">
- </pre>
</div>
+ <div class="hidden" id="loader">
+ <img src="load.gif" />
+ </div>
+
+ <red class="hidden" id="error">
+ </red>
+
+ <pre class="hidden" id="json">
+ </pre>
+
<div id="no-support">
@@ -80,9 +63,6 @@
if (detect ()) {
$("#no-support").remove ();
$("#content").removeClass ("hidden");
-
- folder=new ChronoShare ("/ndn/ucla.edu/alex/macbook", "testing7");
- folder.run ();
}
});
</script>
diff --git a/gui/html/style.css b/gui/html/style.css
index 198e2ef..4b7322d 100644
--- a/gui/html/style.css
+++ b/gui/html/style.css
@@ -116,7 +116,7 @@
}
/* */
-.file-list
+.item-list
{
border-radius: 6px;
@@ -130,7 +130,7 @@
/* border-collapse: collapse; */
}
-.file-list th
+.item-list th
{
/* -moz-border-radius: 10px; */
/* border-radius: 10px; */
@@ -144,13 +144,13 @@
text-align: left;
}
-.file-list th.border-left {
+.item-list th.border-left {
/* -moz-border-radius-topleft:10px; */
/* -webkit-border-top-left-radius:10px; */
/* border-top-left-radius:10px; */
}
-.file-list td
+.item-list td
{
padding: 8px;
border-bottom: 1px solid #fff;
@@ -172,7 +172,7 @@
border-bottom: 2px solid #99CCB2;
background: #EAF4EF;
}
-.file-list tfoot td {
+.item-list tfoot td {
padding: 0;
}
@@ -181,6 +181,11 @@
background-color: #eeeeee;
}
+.highlighted {
+ background-color: #cccccc;
+ cursor: pointer;
+}
+
.filename {
width: 50%;
}
@@ -207,3 +212,13 @@
margin-top: -64px; /* Half the height */
margin-left: -64px; /* Half the width */
}
+
+userName {
+ display: inline-block;
+ /* ? how format user name? */
+}
+
+seqNo {
+ display: inline-block;
+ margin-left: 5px;
+}
\ No newline at end of file
diff --git a/server/mime_types.cpp b/server/mime_types.cpp
index eb86fdf..a2d0b15 100644
--- a/server/mime_types.cpp
+++ b/server/mime_types.cpp
@@ -24,6 +24,7 @@
{ "htm", "text/html" },
{ "html", "text/html" },
{ "css", "text/css" },
+ { "js", "text/javascript" },
{ "jpg", "image/jpeg" },
{ "png", "image/png" },
{ 0, 0 } // Marks end of list.
diff --git a/src/state-server.cc b/src/state-server.cc
index e70b891..fa8517c 100644
--- a/src/state-server.cc
+++ b/src/state-server.cc
@@ -164,15 +164,16 @@
json.push_back (Pair ("id", id));
- json.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.timestamp ()))));
+ json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.timestamp ()))));
json.push_back (Pair ("filename", action.filename ()));
+ json.push_back (Pair ("version", action.version ()));
json.push_back (Pair ("action", (action.action () == 0) ? "UPDATE" : "DELETE"));
if (action.action () == 0)
{
Object update;
update.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (action.file_hash ().c_str (), action.file_hash ().size ()))));
- update.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.mtime ()))));
+ update.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.mtime ()))));
ostringstream chmod;
chmod << setbase (8) << setfill ('0') << setw (4) << action.mode ();
@@ -304,7 +305,7 @@
}
json.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (file.file_hash ().c_str (), file.file_hash ().size ()))));
- json.push_back (Pair ("timestamp", to_iso_string (from_time_t (file.mtime ()))));
+ json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (file.mtime ()))));
ostringstream chmod;
chmod << setbase (8) << setfill ('0') << setw (4) << file.mode ();