/** * Backbone model denoting the remote Fuseki server. */ define( function( require ) { "use strict"; var Marionette = require( "marionette" ), Backbone = require( "backbone" ), _ = require( "underscore" ), fui = require( "app/fui" ), sprintf = require( "sprintf" ), Dataset = require( "app/models/dataset" ), PageUtils = require( "app/util/page-utils" ); var DATASETS_MANAGEMENT_PATH = "/$/datasets"; /** * This model represents the core representation of the remote Fuseki * server. Individual datasets have their own model. */ var FusekiServer = Backbone.Model.extend( { /** This initializer occurs when the module starts, not when the constructor is invoked */ init: function( options ) { this._baseURL = this.currentRootPath(); this._managementURL = null; this.set( "selectedDatasetName", PageUtils.queryParam( "ds" ) ) }, baseURL: function() { return this._baseURL; }, /** Return the URL from which we extract the details of the current server */ serverDetailsURL: function() { return sprintf( "%s/$/server", this.baseURL() ); }, /** Return the URL for issuing commands to the management API, or null if no API defined */ managementURL: function() { return this._managementURL; }, /** Return the URL for getting the stats for all datasets */ statsURL: function() { return sprintf( "%s/$/stats", this.managementURL() ); }, /** Return the list of datasets that this server knows about. Each dataset will be a Dataset model object */ datasets: function() { return this.get( "datasets" ); }, /** Return the dataset with the given name */ dataset: function( dsName ) { return _.find( this.datasets(), function( ds ) {return dsName === ds.name();} ) }, /** Return the name of the currently selected dataset, if known */ selectedDatasetName: function() { return this.get( "selectedDatasetName" ); }, /** Return the dataset that is currently selected, or null */ selectedDataset: function() { var dsName = this.selectedDatasetName(); return dsName && this.dataset( dsName ); }, /** Load and cache the remote server description. Trigger change event when done */ loadServerDescription: function() { var self = this; return this.getJSON( this.serverDetailsURL() ) .done( function( data ) { self.saveServerDescription( data ); } ) .then( function() { fui.vent.trigger( "models.fuseki-server.ready" ); }); }, /** Store the server description in this model */ saveServerDescription: function( serverDesc ) { // wrap each dataset JSON description as a dataset model var bURL = this.baseURL(); var mgmtURL = bURL; if (serverDesc.admin) { // This is too simple. window.location.port may be empty and matches protocol. //mgmtURL = bURL.replace( ":" + window.location.port, ":" + serverDesc.admin.port ); //console.log("managementURL -- s/"+window.location.port+"/"+serverDesc.admin.port+"/") ; var path = window.location.pathname.replace( /\/[^/]*$/, "" ) ; mgmtURL = sprintf( "%s//%s:%s%s", window.location.protocol, window.location.hostname, serverDesc.admin, path ); } this._managementURL = mgmtURL ; var datasets = _.map( serverDesc.datasets, function( d ) { return new Dataset( d, bURL, mgmtURL + DATASETS_MANAGEMENT_PATH ); } ); datasets.sort( function( ds0, ds1 ) { if (ds0.name() > ds1.name()) { return 1; } else if (ds0.name() < ds1.name()) { return -1; } else return 0; } ); this.set( { serverDescription: serverDesc, datasets: datasets, ready: true } ); }, /** * Get the given relative path from the server, and return a promise object which will * complete with the JSON object denoted by the path. */ getJSON: function( path, data ) { return $.getJSON( path, data ); }, /** Update or create a dataset by posting to its endpoint */ updateOrCreateDataset: function( datasetId, data ) { var url = sprintf( "%s/$/datasets%s", this.managementURL(), datasetId ? ("/" + datasetId) : "" ); return $.ajax( url, { data: data, method: "post" } ); }, /** Extract the server root path from the current window href * This is the path, from /, without protocol, host or port. * Then the browser adds protocol, host or port. * Sometimes, the app does not know URL the browser used. * For example, in docker, the port may have been remapped, * or with a reverse proxy, https may have been terminated. */ currentRootPath: function() { var path = window.location.pathname.replace( /\/[^/]*$/, "" ); /* console.log("window.location="+window.location) ; console.log("window.location.href="+window.location.href) ; console.log("window.location.protocol="+window.location.protocol) ; console.log("window.location.host="+window.location.host) ; console.log("window.location.hostname="+window.location.hostname) ; console.log("window.location.port="+window.location.port) ; console.log("window.location.pathname="+window.location.pathname) ; console.log("window.location.origin="+window.location.origin) ; console.log("window.location.hash="+window.location.hash) ; console.log("window.location.search="+window.location.search) ; console.log("path='"+path+"'") ; */ return path ; } } ); // when the models module starts, automatically load the server description fui.models.addInitializer( function( options ) { var fusekiServer = new FusekiServer(); fui.models.fusekiServer = fusekiServer; fusekiServer.init( options ); fusekiServer.loadServerDescription(); } ); return FusekiServer; } );