mirror of https://github.com/perkeep/perkeep.git
Merge "show server status on index page"
This commit is contained in:
commit
b815a01347
|
@ -11,6 +11,7 @@
|
|||
"handlerArgs": {
|
||||
"ownerName": ["_env", "${USER}-dev"],
|
||||
"blobRoot": "/bs-and-maybe-also-index/",
|
||||
"statusRoot": "/status/",
|
||||
"searchRoot": "/my-search/",
|
||||
"stealth": false
|
||||
}
|
||||
|
@ -58,6 +59,10 @@
|
|||
}
|
||||
},
|
||||
|
||||
"/status/": {
|
||||
"handler": "status"
|
||||
},
|
||||
|
||||
"/sync/": {
|
||||
"handler": "sync",
|
||||
"handlerArgs": {
|
||||
|
|
|
@ -44,6 +44,7 @@ type RootHandler struct {
|
|||
// search root.
|
||||
BlobRoot string
|
||||
SearchRoot string
|
||||
statusRoot string
|
||||
|
||||
Storage blobserver.Storage // of BlobRoot, or nil
|
||||
|
||||
|
@ -75,6 +76,7 @@ func newRootFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handle
|
|||
OwnerName: conf.OptionalString("ownerName", u.Name),
|
||||
}
|
||||
root.Stealth = conf.OptionalBool("stealth", false)
|
||||
root.statusRoot = conf.OptionalString("statusRoot", "")
|
||||
if err = conf.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -163,6 +165,7 @@ func (rh *RootHandler) serveDiscovery(rw http.ResponseWriter, req *http.Request)
|
|||
"blobRoot": rh.BlobRoot,
|
||||
"searchRoot": rh.SearchRoot,
|
||||
"ownerName": rh.OwnerName,
|
||||
"statusRoot": rh.statusRoot,
|
||||
}
|
||||
if gener, ok := rh.Storage.(blobserver.Generationer); ok {
|
||||
initTime, gen, err := gener.StorageGeneration()
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright 2013 The Camlistore Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"camlistore.org/pkg/blobserver"
|
||||
"camlistore.org/pkg/buildinfo"
|
||||
"camlistore.org/pkg/httputil"
|
||||
"camlistore.org/pkg/jsonconfig"
|
||||
)
|
||||
|
||||
// StatusHandler publishes server status information.
|
||||
type StatusHandler struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func init() {
|
||||
blobserver.RegisterHandlerConstructor("status", newStatusFromConfig)
|
||||
}
|
||||
|
||||
func newStatusFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, err error) {
|
||||
sh := &StatusHandler{
|
||||
Version: buildinfo.Version(),
|
||||
}
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
func (sh *StatusHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
suffix := req.Header.Get("X-PrefixHandler-PathSuffix")
|
||||
if req.Method != "GET" {
|
||||
http.Error(rw, "Illegal URL.", 404)
|
||||
}
|
||||
if suffix == "status.json" {
|
||||
sh.serveStatus(rw, req)
|
||||
return
|
||||
}
|
||||
http.Error(rw, "Illegal URL.", 404)
|
||||
}
|
||||
|
||||
type statusResponse struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func (sh *StatusHandler) serveStatus(rw http.ResponseWriter, req *http.Request) {
|
||||
res := &statusResponse{
|
||||
Version: sh.Version,
|
||||
}
|
||||
|
||||
httputil.ReturnJSON(rw, res)
|
||||
}
|
|
@ -253,6 +253,7 @@ func genLowLevelPrefixes(params *configPrefixesParams) (m jsonconfig.Obj) {
|
|||
"handlerArgs": map[string]interface{}{
|
||||
"stealth": false,
|
||||
"blobRoot": root,
|
||||
"statusRoot": "/status/",
|
||||
},
|
||||
}
|
||||
if haveIndex {
|
||||
|
@ -263,6 +264,10 @@ func genLowLevelPrefixes(params *configPrefixesParams) (m jsonconfig.Obj) {
|
|||
"handler": "setup",
|
||||
}
|
||||
|
||||
m["/status/"] = map[string]interface{}{
|
||||
"handler": "status",
|
||||
}
|
||||
|
||||
if params.shareHandler {
|
||||
m["/share/"] = map[string]interface{}{
|
||||
"handler": "share",
|
||||
|
|
|
@ -298,7 +298,7 @@ func handerTypeWantsAuth(handlerType string) bool {
|
|||
// TODO(bradfitz): ask the handler instead? This is a bit of a
|
||||
// weird spot for this policy maybe?
|
||||
switch handlerType {
|
||||
case "ui", "search", "jsonsign", "sync":
|
||||
case "ui", "search", "jsonsign", "sync", "status":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
.cam-index-page {
|
||||
font: 16px/1.4 normal Arial, sans-serif;
|
||||
font: 16px/1.4 normal Arial, sans-serif;
|
||||
}
|
||||
|
||||
.cam-index-title {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cam-index-serverinfo {
|
||||
display: inline;
|
||||
float: right;
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@ goog.require('goog.dom.classes');
|
|||
goog.require('goog.events.EventHandler');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.ui.Component');
|
||||
goog.require('goog.ui.Textarea');
|
||||
goog.require('camlistore.BlobItemContainer');
|
||||
goog.require('camlistore.ServerConnection');
|
||||
goog.require('camlistore.Toolbar');
|
||||
goog.require('camlistore.Toolbar.EventType');
|
||||
goog.require('camlistore.ServerType');
|
||||
|
||||
|
||||
/**
|
||||
|
@ -47,6 +49,12 @@ camlistore.IndexPage = function(config, opt_domHelper) {
|
|||
this.connection_, opt_domHelper);
|
||||
this.blobItemContainer_.setHasCreateItem(true);
|
||||
|
||||
/**
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.serverInfo_;
|
||||
|
||||
/**
|
||||
* @type {camlistore.Toolbar}
|
||||
* @private
|
||||
|
@ -81,10 +89,13 @@ camlistore.IndexPage.prototype.decorateInternal = function(element) {
|
|||
var el = this.getElement();
|
||||
goog.dom.classes.add(el, 'cam-index-page');
|
||||
|
||||
var titleEl = this.dom_.createDom('h1', 'cam-index-page-title');
|
||||
var titleEl = this.dom_.createDom('h1', 'cam-index-title');
|
||||
this.dom_.setTextContent(titleEl, this.config_.ownerName + '\'s Vault');
|
||||
this.dom_.appendChild(el, titleEl);
|
||||
|
||||
this.serverInfo_ = this.dom_.createDom('div', 'cam-index-serverinfo');
|
||||
this.dom_.appendChild(el, this.serverInfo_);
|
||||
|
||||
this.addChild(this.toolbar_, true);
|
||||
this.addChild(this.blobItemContainer_, true);
|
||||
};
|
||||
|
@ -103,6 +114,12 @@ camlistore.IndexPage.prototype.disposeInternal = function() {
|
|||
camlistore.IndexPage.prototype.enterDocument = function() {
|
||||
camlistore.IndexPage.superClass_.enterDocument.call(this);
|
||||
|
||||
this.connection_.serverStatus(
|
||||
goog.bind(function(resp) {
|
||||
this.handleServerStatus_(resp);
|
||||
}, this)
|
||||
);
|
||||
|
||||
this.eh_.listen(
|
||||
this.toolbar_, camlistore.Toolbar.EventType.BIGGER,
|
||||
function() {
|
||||
|
@ -273,3 +290,22 @@ camlistore.IndexPage.prototype.addItemsToSetDone_ = function(permanode) {
|
|||
this.toolbar_.toggleAddToSetButton(false);
|
||||
this.blobItemContainer_.showRecent();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {camlistore.ServerType.StatusResponse} resp response for a status request
|
||||
* @private
|
||||
*/
|
||||
camlistore.IndexPage.prototype.handleServerStatus_ =
|
||||
function(resp) {
|
||||
if (resp == null) {
|
||||
return;
|
||||
}
|
||||
goog.dom.removeChildren(this.serverInfo_);
|
||||
if (resp.version) {
|
||||
var version = "Camlistore version: " + resp.version + "\n";
|
||||
var div = this.dom_.createDom('div');
|
||||
goog.dom.setTextContent(div, version);
|
||||
goog.dom.appendChild(this.serverInfo_, div);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -142,6 +142,24 @@ function(success, opt_fail) {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {function(camlistore.ServerType.StatusResponse)} success.
|
||||
* @param {?Function} opt_fail optional failure calback
|
||||
*/
|
||||
camlistore.ServerConnection.prototype.serverStatus =
|
||||
function(success, opt_fail) {
|
||||
var path = goog.uri.utils.appendPath(
|
||||
this.config_.statusRoot, 'status.json'
|
||||
);
|
||||
|
||||
this.sendXhr_(path,
|
||||
goog.bind(this.handleXhrResponseJson_, this,
|
||||
success, this.safeFail_(opt_fail)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Function} success Success callback.
|
||||
* @param {?Function} opt_fail Optional fail callback.
|
||||
|
|
|
@ -23,6 +23,7 @@ camlistore.ServerType.DiscoveryRoot;
|
|||
* ownerName: string,
|
||||
* publishRoots: Array.<camlistore.ServerType.DiscoveryRoot>,
|
||||
* searchRoot: string,
|
||||
* statusRoot: string,
|
||||
* storageGeneration: string,
|
||||
* storageInitTime: string,
|
||||
* signing: camlistore.ServerType.SigningDiscoveryDocument,
|
||||
|
@ -128,3 +129,10 @@ camlistore.ServerType.SearchWithAttrResponse;
|
|||
* }}
|
||||
*/
|
||||
camlistore.ServerType.DescribeResponse;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* }}
|
||||
*/
|
||||
camlistore.ServerType.StatusResponse;
|
||||
|
|
Loading…
Reference in New Issue