Merge branch 'adamierymenko-dev' into android-jni

This commit is contained in:
Grant Limberg 2015-05-06 17:37:11 -07:00
commit 20b76d266d
12 changed files with 16097 additions and 31 deletions

View File

@ -37,8 +37,7 @@
#include "../node/InetAddress.hpp"
#include "../node/Node.hpp"
#include "../node/Utils.hpp"
#define ZT_BUILD_IN_WEB_UI
#include "../osdep/OSUtils.hpp"
namespace ZeroTier {
@ -242,9 +241,10 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT1_Peer *peer
buf.append(json);
}
ControlPlane::ControlPlane(OneService *svc,Node *n) :
ControlPlane::ControlPlane(OneService *svc,Node *n,const char *uiStaticPath) :
_svc(svc),
_node(n)
_node(n),
_uiStaticPath((uiStaticPath) ? uiStaticPath : "")
{
}
@ -316,31 +316,34 @@ unsigned int ControlPlane::handleRequest(
* dot in the first path element (e.g. foo.html) is considered a static page,
* as nothing in the API is so named. */
#ifdef ZT_BUILD_IN_WEB_UI
if (ext == ".html")
responseContentType = "text/html";
else if (ext == ".js")
responseContentType = "application/javascript";
else if (ext == ".json")
responseContentType = "application/json";
else if (ext == ".css")
responseContentType = "text/css";
else if (ext == ".png")
responseContentType = "image/png";
else if (ext == ".jpg")
responseContentType = "image/jpeg";
else if (ext == ".gif")
responseContentType = "image/gif";
else if (ext == ".txt")
responseContentType = "text/plain";
else if (ext == ".xml")
responseContentType = "text/xml";
else if (ext == ".svg")
responseContentType = "image/svg+xml";
else responseContentType = "application/octet-stream";
responseBody = "<html><body>Hello World!</body></html>";
scode = 200;
#endif // ZT_BUILD_IN_WEB_UI
if (_uiStaticPath.length() > 0) {
if (ext == ".html")
responseContentType = "text/html";
else if (ext == ".js")
responseContentType = "application/javascript";
else if (ext == ".jsx")
responseContentType = "text/jsx";
else if (ext == ".json")
responseContentType = "application/json";
else if (ext == ".css")
responseContentType = "text/css";
else if (ext == ".png")
responseContentType = "image/png";
else if (ext == ".jpg")
responseContentType = "image/jpeg";
else if (ext == ".gif")
responseContentType = "image/gif";
else if (ext == ".txt")
responseContentType = "text/plain";
else if (ext == ".xml")
responseContentType = "text/xml";
else if (ext == ".svg")
responseContentType = "image/svg+xml";
else responseContentType = "application/octet-stream";
scode = OSUtils::readFile((_uiStaticPath + ZT_PATH_SEPARATOR_S + ps[0]).c_str(),responseBody) ? 200 : 404;
} else {
scode = 404;
}
} else if (isAuth) {
/* Things that require authentication -- a.k.a. everything but static web app pages. */

View File

@ -49,7 +49,7 @@ struct InetAddress;
class ControlPlane
{
public:
ControlPlane(OneService *svc,Node *n);
ControlPlane(OneService *svc,Node *n,const char *uiStaticPath);
~ControlPlane();
/**
@ -102,6 +102,7 @@ public:
private:
OneService *const _svc;
Node *const _node;
std::string _uiStaticPath;
std::set<std::string> _authTokens;
std::map<std::string,ControlPlaneSubsystem *> _subsystems;
Mutex _lock;

View File

@ -226,7 +226,7 @@ public:
if (_master)
_node->setNetconfMaster((void *)_master);
_controlPlane = new ControlPlane(this,_node);
_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
_controlPlane->addAuthToken(authToken.c_str());
if (_master)
_controlPlane->mount("controller",reinterpret_cast<ControlPlaneSubsystem *>(_master));

15919
ui/JSXTransformer.js Normal file

File diff suppressed because one or more lines are too long

51
ui/ZeroTierNode.jsx Normal file
View File

@ -0,0 +1,51 @@
var ZeroTierNode = React.createClass({
getInitialState: function() {
return {
address: '----------',
online: false,
version: '_._._'
};
},
updateAll: function() {
Ajax.call({
url: 'status?auth='+this.props.authToken,
cache: false,
type: 'GET',
success: function(data) {
if (data)
this.setState(JSON.parse(data));
}.bind(this),
error: function() {
this.setState(this.getInitialState());
}.bind(this)
})
},
componentDidMount: function() {
this.updateAll();
// this.updateIntervalId = setInterval(this.updateAll,2500);
},
componentWillUnmount: function() {
// clearInterval(this.updateIntervalId);
},
render: function() {
return (
<div className="container-fluid zeroTierNode">
<div className="row">
</div>
<div className="row">
<div className="col-xs-8">
<span className="zerotier-address">{this.state.address}</span>
<span className="zerotier-node-statusline">{this.state.online ? 'ONLINE' : 'OFFLINE'}&nbsp;&nbsp;{this.state.version}</span>
</div>
<div className="col-xs-4">
<form>
<input type="text"/>
</form>
</div>
</div>
</div>
);
}
});

5
ui/bootstrap-theme.min.css vendored Normal file

File diff suppressed because one or more lines are too long

5
ui/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

22
ui/index.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>ZeroTier One</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="bootstrap-theme.min.css">
<link rel="stylesheet" href="zerotier.css">
<script src="simpleajax.min.js"></script>
<script src="react.min.js"></script>
<script src="JSXTransformer.js"></script>
<script type="text/jsx" src="ZeroTierNode.jsx"></script>
<script type="text/jsx" src="main.jsx"></script>
</head>
<body>
<div style="width: 100%; height: 100%;" id="main"></div>
</body>
</html>

4
ui/main.jsx Normal file
View File

@ -0,0 +1,4 @@
React.render(
<ZeroTierNode authToken={'5d6181b71fae2684f9cc64ed'} />,
document.getElementById('main')
);

15
ui/react.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
ui/simpleajax.min.js vendored Normal file
View File

@ -0,0 +1,2 @@
/** SimpleAjax v1.0.1 - MIT license - https://github.com/freelancephp/SimpleAjax */
(function(window){var SimpleAjax=window.SimpleAjax={xhr:null,settings:{url:"",type:"GET",dataType:"text",async:true,cache:true,data:null,contentType:"application/x-www-form-urlencoded",success:null,error:null,complete:null,accepts:{text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"}},call:function(a){var b=this,c=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),d=function(a,b){var c={};for(var d in a)c[d]=typeof b[d]=="undefined"?a[d]:b[d];return c}(this.settings,a),e=function(){if(c.readyState==4){if(c.status>=200&&c.status<300||c.status===304){var a=d.dataType=="xml"?c.responseXML:c.responseText;if(d.dataType=="json")a=b.parseJSON(a);if(b.isFunction(d.success))d.success.call(d,a,c.status,c)}else{if(b.isFunction(d.error))d.error.call(d,c,c.status)}if(b.isFunction(d.complete))d.complete.call(d,c,c.status)}};this.xhr=c;if(!d.cache)d.url+=(d.url.indexOf("?")>-1?"&":"?")+"_nocache="+(new Date).getTime();if(d.data){if(d.type=="GET"){d.url+=(d.url.indexOf("?")>-1?"&":"?")+this.param(d.data);d.data=null}else{d.data=this.param(d.data)}}c.open(d.type,d.url,d.async);c.setRequestHeader("Content-type",d.contentType);if(d.dataType&&d.accepts[d.dataType])c.setRequestHeader("Accept",d.accepts[d.dataType]);if(d.async){c.onreadystatechange=e;c.send(d.data)}else{c.send(d.data);e()}return this},get:function(a,b,c){if(this.isFunction(b)){c=b;b=null}return this.call({url:a,type:"GET",data:b,success:c})},post:function(a,b,c){if(this.isFunction(b)){c=b;b=null}return this.call({url:a,type:"POST",data:b,success:c})},load:function(a,b,c,d){if(typeof a=="string")a=document.getElementById(a);return this.call({url:b,type:c?"POST":"GET",data:c||null,complete:d||null,success:function(b){try{a.innerHTML=b}catch(c){var d=document.createElement("div");d.innerHTML=b;while(a.firstChild)a.removeChild(a.firstChild);for(var e=0,f=d.childNodes.length;e<f;e++)a.appendChild(d.childNodes[e])}}})},param:function(a){var b=[];for(var c in a){b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]))}return b.join("&")},parseJSON:function(data){if(typeof data!=="string"||!data)return null;return eval("("+this.trim(data)+")")},trim:function(a){return a.replace(/^\s+/,"").replace(/\s+$/,"")},isFunction:function(a){return Object.prototype.toString.call(a)==="[object Function]"}};if(!window.Ajax){window.Ajax=SimpleAjax}})(window)

39
ui/zerotier.css Normal file
View File

@ -0,0 +1,39 @@
/* Dark blue-grey: #234447
* Light blue-grey: #91a2a3
* Light yellow: #ffffcc
* Orange: #ffb354 */
/*
@font-face {
font-family: 'Clear Sans Thin';
src: url('fonts/clearsans_thin/ClearSans-Thin-webfont.eot');
src: url('fonts/clearsans_thin/ClearSans-Thin-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.woff') format('woff'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.ttf') format('truetype'), url('fonts/clearsans_thin/ClearSans-Thin-webfont.svg#clear_sans_thinregular') format('svg');
font-weight: normal;
font-style: normal;
}
*/
/*
@font-face {
font-family: 'Clear Sans Regular';
src: url('ClearSans-Regular-webfont.eot');
src: url('ClearSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('ClearSans-Regular-webfont.woff') format('woff'), url('ClearSans-Regular-webfont.ttf') format('truetype'), url('ClearSans-Regular-webfont.svg#clear_sansregular') format('svg');
font-weight: normal;
font-style: normal;
}
*/
html,body {
font-family: "Helvetica Neue","Lucida Sans Unicode",sans-serif;
font-size: 12pt;
margin: 0;
padding: 0;
width: 100%;
}
.zerotier-address {
font-family: monospace;
}
.zerotier-node-statusline {
font-size: smaller;
padding: 0 0.75rem 0 0.75rem;
}