fuseki-server.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * Backbone model denoting the remote Fuseki server.
  3. */
  4. define(
  5. function( require ) {
  6. "use strict";
  7. var Marionette = require( "marionette" ),
  8. Backbone = require( "backbone" ),
  9. _ = require( "underscore" ),
  10. fui = require( "app/fui" ),
  11. sprintf = require( "sprintf" ),
  12. Dataset = require( "app/models/dataset" ),
  13. PageUtils = require( "app/util/page-utils" );
  14. var DATASETS_MANAGEMENT_PATH = "/$/datasets";
  15. /**
  16. * This model represents the core representation of the remote Fuseki
  17. * server. Individual datasets have their own model.
  18. */
  19. var FusekiServer = Backbone.Model.extend( {
  20. /** This initializer occurs when the module starts, not when the constructor is invoked */
  21. init: function( options ) {
  22. this._baseURL = this.currentRootPath();
  23. this._managementURL = null;
  24. this.set( "selectedDatasetName", PageUtils.queryParam( "ds" ) )
  25. },
  26. baseURL: function() {
  27. return this._baseURL;
  28. },
  29. /** Return the URL from which we extract the details of the current server */
  30. serverDetailsURL: function() {
  31. return sprintf( "%s/$/server", this.baseURL() );
  32. },
  33. /** Return the URL for issuing commands to the management API, or null if no API defined */
  34. managementURL: function() {
  35. return this._managementURL;
  36. },
  37. /** Return the URL for getting the stats for all datasets */
  38. statsURL: function() {
  39. return sprintf( "%s/$/stats", this.managementURL() );
  40. },
  41. /** Return the list of datasets that this server knows about. Each dataset will be a Dataset model object */
  42. datasets: function() {
  43. return this.get( "datasets" );
  44. },
  45. /** Return the dataset with the given name */
  46. dataset: function( dsName ) {
  47. return _.find( this.datasets(), function( ds ) {return dsName === ds.name();} )
  48. },
  49. /** Return the name of the currently selected dataset, if known */
  50. selectedDatasetName: function() {
  51. return this.get( "selectedDatasetName" );
  52. },
  53. /** Return the dataset that is currently selected, or null */
  54. selectedDataset: function() {
  55. var dsName = this.selectedDatasetName();
  56. return dsName && this.dataset( dsName );
  57. },
  58. /** Load and cache the remote server description. Trigger change event when done */
  59. loadServerDescription: function() {
  60. var self = this;
  61. return this.getJSON( this.serverDetailsURL() )
  62. .done( function( data ) {
  63. self.saveServerDescription( data );
  64. } )
  65. .then( function() {
  66. fui.vent.trigger( "models.fuseki-server.ready" );
  67. });
  68. },
  69. /** Store the server description in this model */
  70. saveServerDescription: function( serverDesc ) {
  71. // wrap each dataset JSON description as a dataset model
  72. var bURL = this.baseURL();
  73. var mgmtURL = bURL;
  74. if (serverDesc.admin) {
  75. // This is too simple. window.location.port may be empty and matches protocol.
  76. //mgmtURL = bURL.replace( ":" + window.location.port, ":" + serverDesc.admin.port );
  77. //console.log("managementURL -- s/"+window.location.port+"/"+serverDesc.admin.port+"/") ;
  78. var path = window.location.pathname.replace( /\/[^/]*$/, "" ) ;
  79. mgmtURL = sprintf( "%s//%s:%s%s", window.location.protocol, window.location.hostname, serverDesc.admin, path );
  80. }
  81. this._managementURL = mgmtURL ;
  82. var datasets = _.map( serverDesc.datasets, function( d ) {
  83. return new Dataset( d, bURL, mgmtURL + DATASETS_MANAGEMENT_PATH );
  84. } );
  85. datasets.sort( function( ds0, ds1 ) {
  86. if (ds0.name() > ds1.name()) {
  87. return 1;
  88. }
  89. else if (ds0.name() < ds1.name()) {
  90. return -1;
  91. }
  92. else
  93. return 0;
  94. } );
  95. this.set( {
  96. serverDescription: serverDesc,
  97. datasets: datasets,
  98. ready: true
  99. } );
  100. },
  101. /**
  102. * Get the given relative path from the server, and return a promise object which will
  103. * complete with the JSON object denoted by the path.
  104. */
  105. getJSON: function( path, data ) {
  106. return $.getJSON( path, data );
  107. },
  108. /** Update or create a dataset by posting to its endpoint */
  109. updateOrCreateDataset: function( datasetId, data ) {
  110. var url = sprintf( "%s/$/datasets%s", this.managementURL(),
  111. datasetId ? ("/" + datasetId) : ""
  112. );
  113. return $.ajax( url,
  114. { data: data,
  115. method: "post"
  116. }
  117. );
  118. },
  119. /** Extract the server root path from the current window href
  120. * This is the path, from /, without protocol, host or port.
  121. * Then the browser adds protocol, host or port.
  122. * Sometimes, the app does not know URL the browser used.
  123. * For example, in docker, the port may have been remapped,
  124. * or with a reverse proxy, https may have been terminated.
  125. */
  126. currentRootPath: function() {
  127. var path = window.location.pathname.replace( /\/[^/]*$/, "" );
  128. /*
  129. console.log("window.location="+window.location) ;
  130. console.log("window.location.href="+window.location.href) ;
  131. console.log("window.location.protocol="+window.location.protocol) ;
  132. console.log("window.location.host="+window.location.host) ;
  133. console.log("window.location.hostname="+window.location.hostname) ;
  134. console.log("window.location.port="+window.location.port) ;
  135. console.log("window.location.pathname="+window.location.pathname) ;
  136. console.log("window.location.origin="+window.location.origin) ;
  137. console.log("window.location.hash="+window.location.hash) ;
  138. console.log("window.location.search="+window.location.search) ;
  139. console.log("path='"+path+"'") ;
  140. */
  141. return path ;
  142. }
  143. } );
  144. // when the models module starts, automatically load the server description
  145. fui.models.addInitializer( function( options ) {
  146. var fusekiServer = new FusekiServer();
  147. fui.models.fusekiServer = fusekiServer;
  148. fusekiServer.init( options );
  149. fusekiServer.loadServerDescription();
  150. } );
  151. return FusekiServer;
  152. }
  153. );