forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathNodeStaticServer.js
More file actions
1 lines (1 loc) · 16 KB
/
Copy pathNodeStaticServer.js
File metadata and controls
1 lines (1 loc) · 16 KB
1
define(function(require,exports,module){const BaseServer=require("LiveDevelopment/Servers/BaseServer").BaseServer,LiveDevelopmentUtils=require("LiveDevelopment/LiveDevelopmentUtils"),LiveDevelopment=require("LiveDevelopment/main"),LiveDevProtocol=require("LiveDevelopment/MultiBrowserImpl/protocol/LiveDevProtocol"),marked=require("thirdparty/marked.min"),DocumentManager=require("document/DocumentManager"),Mustache=require("thirdparty/mustache/mustache"),FileSystem=require("filesystem/FileSystem"),EventDispatcher=require("utils/EventDispatcher"),LivePreviewSettings=require("./LivePreviewSettings"),ProjectManager=require("project/ProjectManager"),EventManager=require("utils/EventManager"),Strings=require("strings"),utils=require("./utils"),NativeApp=require("utils/NativeApp"),Dialogs=require("widgets/Dialogs"),StringUtils=require("utils/StringUtils"),NodeConnector=require("NodeConnector"),LivePreviewTabs=require("./LivePreviewTabs"),BootstrapCSSText=require("text!thirdparty/bootstrap/bootstrap.min.css"),GithubCSSText=require("text!thirdparty/highlight.js/styles/github.min.css"),HilightJSText=require("text!thirdparty/highlight.js/highlight.min.js"),GFMCSSText=require("text!thirdparty/gfm.min.css"),markdownHTMLTemplate=require("text!./markdown.html"),redirectionHTMLTemplate=require("text!./redirectPage.html"),LIVE_SERVER_NODE_CONNECTOR_ID="ph_live_server",PREVIEW_PORT_KEY="preview_port",EVENT_EMBEDDED_IFRAME_HREF_CLICK="embeddedIframeHrefClick",EVENT_EMBEDDED_IFRAME_ESCAPE_PRESS="embeddedEscapeKeyPressed";let liveServerConnector,staticServerURL,livePreviewCommURL;function _getProjectPreferredPort(projectPath){const preferredPortKey=`${PREVIEW_PORT_KEY}-${projectPath}`;return PhStore.getItem(preferredPortKey)}function _setProjectPreferredPort(projectPath,port){const preferredPortKey=`${PREVIEW_PORT_KEY}-${projectPath}`;PhStore.setItem(preferredPortKey,port)}const EVENT_TAB_ONLINE="TAB_ONLINE",EVENT_SERVER_READY="SERVER_READY";EventDispatcher.makeEventDispatcher(exports);const livePreviewTabs=LivePreviewTabs.livePreviewTabs,PHCODE_LIVE_PREVIEW_QUERY_PARAM="phcodeLivePreview";let _staticServerInstance,projectServerPort=0,_lastPreviewedFilePath;function getNoPreviewURL(heading=Strings.DESCRIPTION_LIVEDEV_NO_PREVIEW,message=Strings.DESCRIPTION_LIVEDEV_NO_PREVIEW_DETAILS){return staticServerURL?`${staticServerURL}phoenix-splash/no-preview.html?jsonInput=`+encodeURIComponent(`{"heading":"${heading}",`+`"details":"${message}"}`):`${window.Phoenix.baseURL}assets/phoenix-splash/no-preview.html?jsonInput=`+encodeURIComponent(`{"heading":"${heading}",`+`"details":"${message}"}`)}function getMdviewrURL(){return`${window.Phoenix.baseURL}mdViewer/index.html`}async function tabLoaderOnline(data){window.logger.livePreview.log("Live Preview navigator channel: tabLoaderOnline: ",data),LivePreviewTabs.tabOnline(data.pageLoaderID,data.URL,!0)}function StaticServer(config){const self=this;this._serverStartPromise=liveServerConnector.execPeer("startStaticServer",{projectRoot:config.root,preferredPort:_getProjectPreferredPort(config.root)}).then(projectConfig=>{projectServerPort=projectConfig.port,self._baseUrl=`http://localhost:${projectServerPort}`,_getProjectPreferredPort(config.root)||_setProjectPreferredPort(config.root,projectConfig.port)}),this._getInstrumentedContent=this._getInstrumentedContent.bind(this),BaseServer.call(this,config)}function _getMarkdown(fullPath){return new Promise((resolve,reject)=>{DocumentManager.getDocumentForPath(fullPath).done(function(doc){let text=doc.getText();text=text.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,"");let markdownHtml,templateVars={markdownContent:marked.parse(text),BOOTSTRAP_LIB_CSS:BootstrapCSSText,HIGHLIGHT_JS_CSS:GithubCSSText,HIGHLIGHT_JS:HilightJSText,TRUSTED_ORIGINS_EMBED:`const TRUSTED_ORIGINS_EMBED = ${JSON.stringify(Phoenix.TRUSTED_ORIGINS)};`,GFM_CSS:GFMCSSText,PARENT_ORIGIN:location.origin},html=Mustache.render(markdownHTMLTemplate,templateVars);resolve({textContents:html,headers:{"Content-Type":"text/html"},path:fullPath})}).fail(function(err){reject(new Error(`Markdown rendering failed for ${fullPath}: `+err))})})}function _getRedirectionPage(redirectURL){let url=new URL(redirectURL);url.searchParams.delete(PHCODE_LIVE_PREVIEW_QUERY_PARAM);let templateVars={redirectURL:_getPageLoaderURL(url.href)};return Mustache.render(redirectionHTMLTemplate,templateVars)}function getContent(url){const currentDocument=DocumentManager.getCurrentDocument(),currentFile=currentDocument?currentDocument.file:ProjectManager.getSelectedItem();if(!_staticServerInstance)return Promise.reject("Static serve not started!");if(!url.startsWith(_staticServerInstance.getBaseUrl()))return Promise.reject("Not serving content as url invalid: "+url);const filePath=_staticServerInstance.urlToPath(url),shouldServeRendered=filePath===_lastPreviewedFilePath||currentFile&¤tFile.fullPath===path;return utils.isMarkdownFile(filePath)&&shouldServeRendered?_getMarkdown(filePath):_staticServerInstance?_staticServerInstance._getInstrumentedContent(filePath,url):Promise.reject("Cannot get content")}function getExternalContent(url){return new Promise((resolve,reject)=>{const currentDocument=DocumentManager.getCurrentDocument(),currentFile=currentDocument?currentDocument.file:ProjectManager.getSelectedItem();url=new URL(url);const requestedFileName=path.basename(url.pathname);if(currentFile&¤tFile.fullPath.endsWith(requestedFileName)){const fullPath=currentFile.fullPath;if(utils.isMarkdownFile(fullPath))return void resolve(_getMarkdown(fullPath));if(utils.isHTMLFile(fullPath)){const pageText=_getRedirectionPage(getNoPreviewURL(Strings.DESCRIPTION_LIVEDEV_PREVIEW_RESTRICTED,Strings.DESCRIPTION_LIVEDEV_PREVIEW_RESTRICTED_DETAILS));return void resolve({path:path,textContents:pageText})}fs.readFile(fullPath,fs.BYTE_ARRAY_ENCODING,function(error,binContent){resolve(error?{path:fullPath,is404:!0}:{path:fullPath,buffer:binContent})})}else resolve({path:url,is404:!0})})}function _startHeartBeatListeners(){LivePreviewTabs.start({close:function(clientID){exports.trigger("BROWSER_CLOSE",{data:{message:{clientID:clientID}}})},reconnect:function(clientID,url){exports.trigger("BROWSER_CONNECT",{data:{message:{clientID:clientID,url:url}}})}})}function messageToLivePreviewTabs(message){if(!message.type)throw new Error("Missing type attribute to send live preview message to tabs");liveServerConnector.execPeer("messageToLivePreviewTabs",message)}async function onLivePreviewMessage(message){switch(message.type){case EVENT_TAB_ONLINE:return void LivePreviewTabs.tabOnline(message.clientID,message.URL);case"BROWSER_CONNECT":LivePreviewTabs.tabConnected(message.clientID,message.url);break;case"BROWSER_CLOSE":LivePreviewTabs.dropTab(message.clientID)}exports.trigger(message.type,{data:{message:message}})}function redirectAllTabs(newURL,force){liveServerConnector.execPeer("navRedirectAllTabs",{type:"REDIRECT_PAGE",URL:getTabPopoutURL(newURL),force:force})}function _projectOpened(_evt,projectRoot){_lastPreviewedFilePath=null,liveServerConnector.execPeer("navMessageProjectOpened",{type:"PROJECT_SWITCH",projectRoot:projectRoot.fullPath})}function _getPageLoaderURL(url){return`${staticServerURL}live-preview-navigator.html?initialURL=${encodeURIComponent(url)}`+`&livePreviewCommURL=${encodeURIComponent(livePreviewCommURL)}`+`&isLoggingEnabled=${logger.loggingOptions.logLivePreview}`}function _getExternalPreviewURL(fullPath){return utils.isHTMLFile(fullPath)?{url:getNoPreviewURL(Strings.DESCRIPTION_LIVEDEV_PREVIEW_RESTRICTED,Strings.DESCRIPTION_LIVEDEV_PREVIEW_RESTRICTED_DETAILS),isNoPreview:!0}:utils.isPreviewableFile(fullPath)?{url:`${staticServerURL}externalProject/${path.basename(fullPath)}`,isNoPreview:!1}:{url:getNoPreviewURL(),isNoPreview:!0}}function getTabPopoutURL(url){let urlToOpen=url;try{let openURL=new URL(url);if(openURL.searchParams.set(PHCODE_LIVE_PREVIEW_QUERY_PARAM,"true"),_staticServerInstance&&utils.isHTMLFile(openURL.pathname)&&url.startsWith(_staticServerInstance.getBaseUrl()))return openURL.href;urlToOpen=openURL.href}catch(e){console.error("Error getting tab popout url",e)}return _getPageLoaderURL(urlToOpen)}function hasActiveLivePreviews(){return livePreviewTabs.size>0}async function getPreviewDetails(){return new Promise(async(resolve,reject)=>{try{const currentDocument=DocumentManager.getCurrentDocument(),currentFile=currentDocument?currentDocument.file:ProjectManager.getSelectedItem();if(!currentFile)return void resolve({URL:getNoPreviewURL(),isNoPreview:!0});const projectRoot=ProjectManager.getProjectRoot().fullPath;let fullPath=currentFile.fullPath;if(!ProjectManager.isWithinProject(fullPath)){const preview=_getExternalPreviewURL(fullPath);return void resolve({URL:preview.url,isNoPreview:preview.isNoPreview,filePath:fullPath,fullPath:fullPath,isMarkdownFile:utils.isMarkdownFile(fullPath),isHTMLFile:utils.isHTMLFile(fullPath)})}let httpFilePath=null;(fullPath.startsWith("http://")||fullPath.startsWith("https://"))&&(httpFilePath=fullPath);const shouldUseInbuiltPreview=utils.isMarkdownFile(fullPath)||utils.isSVG(fullPath),customServeURL=LivePreviewSettings.getCustomServerConfig(fullPath);if(customServeURL){const relativePath=path.relative(projectRoot,fullPath);return void resolve({URL:customServeURL,filePath:relativePath,fullPath:fullPath,isMarkdownFile:utils.isMarkdownFile(fullPath),isHTMLFile:utils.isHTMLFile(fullPath),isCustomServer:!0,serverSupportsHotReload:LivePreviewSettings.serverSupportsHotReload()})}if(LivePreviewSettings.isUsingCustomServer()&&!customServeURL&&!shouldUseInbuiltPreview)return void resolve({URL:getNoPreviewURL(Strings.DESCRIPTION_LIVEDEV_EXCLUDED,StringUtils.format(Strings.DESCRIPTION_LIVEDEV_NO_PREVIEW_EXCLUDED,LivePreviewSettings.getCustomServeRoot())),isNoPreview:!0});if(!_staticServerInstance||!_staticServerInstance.getBaseUrl())return void resolve({URL:getNoPreviewURL(),isNoPreview:!0,isServerNotReady:!0});utils.isPreviewableFile(fullPath)&&(_lastPreviewedFilePath=fullPath);let fileExists=await FileSystem.existsAsync(_lastPreviewedFilePath);if(_lastPreviewedFilePath&&fileExists){const relativeFilePath=httpFilePath||path.relative(projectRoot,_lastPreviewedFilePath);let URL;return void resolve({URL:httpFilePath||decodeURI(_staticServerInstance.pathToUrl(_lastPreviewedFilePath)),filePath:relativeFilePath,fullPath:_lastPreviewedFilePath,isMarkdownFile:utils.isMarkdownFile(_lastPreviewedFilePath),isHTMLFile:utils.isHTMLFile(_lastPreviewedFilePath)})}resolve({URL:getNoPreviewURL(),isNoPreview:!0})}catch(e){reject(e)}})}function getRemoteTransportScript(){return`TRANSPORT_CONFIG.LIVE_PREVIEW_WEBSOCKET_CHANNEL_URL = "${livePreviewCommURL}";\n`}marked.setOptions({renderer:new marked.Renderer,pedantic:!1,gfm:!0,breaks:!1,sanitize:!1,smartLists:!0,smartypants:!1,xhtml:!1}),StaticServer.prototype=Object.create(BaseServer.prototype),StaticServer.prototype.constructor=StaticServer,StaticServer.prototype.getBaseUrl=function(){return this._baseUrl},StaticServer.prototype.pathToUrl=function(path){const baseUrl=this.getBaseUrl(),relativePath=this._pathResolver(path);return relativePath!==path?`${baseUrl}/${encodeURI(relativePath)}`:null},StaticServer.prototype.urlToPath=function(url){let baseUrl=this.getBaseUrl()||"";const projectRoot=this.getProjectRoot();if(""!==baseUrl&&url.startsWith(baseUrl)){const urlObj=new URL(url);let relativePath=decodeURI(urlObj.pathname);return relativePath.startsWith("/")&&(relativePath=(relativePath=path.normalize(relativePath)).slice(1)),`${projectRoot}${relativePath}`}return null},StaticServer.prototype.canServe=function(localPath){return localPath!==this._pathResolver(localPath)&&(!!localPath.match(/\/$/)||LiveDevelopmentUtils.isStaticHtmlFileExt(localPath))},StaticServer.prototype.readyToServe=function(){const result=new $.Deferred;return this._serverStartPromise.then(()=>{exports.trigger("SERVER_READY");const baseUrl=this.getBaseUrl();EventManager.setTrustedOrigin(baseUrl,!0),result.resolve()}).catch(err=>{logger.reportError(err);const baseUrl=this.getBaseUrl();EventManager.setTrustedOrigin(baseUrl,!1),result.reject()}),result.promise()},StaticServer.prototype.addVirtualContentAtPath=function(path,docText){BaseServer.prototype.addVirtualContentAtPath.call(this,path,docText)},StaticServer.prototype.add=function(liveDocument){liveDocument.setInstrumentationEnabled&&liveDocument.setInstrumentationEnabled(!0),BaseServer.prototype.add.call(this,liveDocument)},StaticServer.prototype.remove=function(liveDocument){BaseServer.prototype.remove.call(this,liveDocument)},StaticServer.prototype.removeVirtualContentAtPath=function(path){BaseServer.prototype.removeVirtualContentAtPath.call(this,path)},StaticServer.prototype.clear=function(){BaseServer.prototype.clear.call(this)},StaticServer.prototype._getInstrumentedContent=function(requestedPath,url){return new Promise((resolve,reject)=>{let path=this._documentKey(requestedPath),liveDocument=this._liveDocuments[path],virtualDocument=this._virtualServingDocuments[path],contents;if(!ProjectManager.isWithinProject(requestedPath))return console.error("Security issue prevented: Live preview tried to access non project resource!!!",path),void resolve({path:path,textContents:Strings.DESCRIPTION_LIVEDEV_SECURITY});let isLivePreviewPopoutPage=!1,headers;if((url=new URL(url)).searchParams.get(PHCODE_LIVE_PREVIEW_QUERY_PARAM)&&(isLivePreviewPopoutPage=!0),virtualDocument)contents=virtualDocument;else if(liveDocument&&liveDocument.getResponseData)contents=liveDocument.getResponseData().body,isLivePreviewPopoutPage&&-1===contents.indexOf(LiveDevProtocol.getRemoteScript())&&(console.log("serving stale live preview with navigable url",url),contents=_getRedirectionPage(url));else{const file=FileSystem.getFileForPath(requestedPath);let doc=DocumentManager.getOpenDocumentForPath(file.fullPath);if(!doc)return void fs.readFile(requestedPath,fs.BYTE_ARRAY_ENCODING,function(error,binContent){resolve(error?{path:path,is404:!0}:{path:path,buffer:binContent})});contents=doc.getText()}(path.endsWith(".htm")||path.endsWith(".html")||path.endsWith(".xhtml")||path.endsWith(".php"))&&(headers={"Content-Type":"text/html;charset=UTF-8"}),resolve({path:path,textContents:contents,headers:headers})})},StaticServer.prototype.start=async function(){_staticServerInstance=this},StaticServer.prototype.isActive=function(){return _staticServerInstance===this},StaticServer.prototype.stop=function(){_staticServerInstance=void 0};let urlsOpenedInLast5Secs=0;const MAX_URLS_OPEN_BEFORE_CONFIRM=4;setInterval(()=>{urlsOpenedInLast5Secs=0},5e3);let dialogIsShown=!1;function init(){window.nodeSetupDonePromise.then(nodeConfig=>{staticServerURL=`${nodeConfig.staticServerURL}/`,livePreviewCommURL=`${nodeConfig.livePreviewCommURL}`}),liveServerConnector=NodeConnector.createNodeConnector(LIVE_SERVER_NODE_CONNECTOR_ID,exports),LiveDevelopment.setLivePreviewTransportBridge(exports),ProjectManager.on(ProjectManager.EVENT_PROJECT_OPEN,_projectOpened),_startHeartBeatListeners(),EventManager.registerEventHandler("ph-liveServer",exports)}exports.on("embeddedIframeHrefClick",function(_ev,event){if(dialogIsShown)return;const href=event.data.href;++urlsOpenedInLast5Secs>=4?(dialogIsShown=!0,Dialogs.showConfirmDialog(Strings.CONFIRM_EXTERNAL_BROWSER_TITLE,StringUtils.format(Strings.CONFIRM_EXTERNAL_BROWSER_MESSAGE,href)).done(id=>{id===Dialogs.DIALOG_BTN_OK&&(urlsOpenedInLast5Secs=0,href&&NativeApp.openURLInDefaultBrowser(href)),dialogIsShown=!1})):href&&NativeApp.openURLInDefaultBrowser(href)}),exports.on("embeddedEscapeKeyPressed",function(){LiveDevelopment.isInPreviewMode()||utils.focusActiveEditorIfFocusInLivePreview()}),exports.init=init,exports.StaticServer=StaticServer,exports.messageToLivePreviewTabs=messageToLivePreviewTabs,exports.livePreviewTabs=livePreviewTabs,exports.dropTab=LivePreviewTabs.dropTab,exports.redirectAllTabs=redirectAllTabs,exports.getTabPopoutURL=getTabPopoutURL,exports.hasActiveLivePreviews=hasActiveLivePreviews,exports.getNoPreviewURL=getNoPreviewURL,exports.getMdviewrURL=getMdviewrURL,exports.getPreviewDetails=getPreviewDetails,exports.getRemoteTransportScript=getRemoteTransportScript,exports.tabLoaderOnline=tabLoaderOnline,exports.getContent=getContent,exports.getExternalContent=getExternalContent,exports.onLivePreviewMessage=onLivePreviewMessage,exports.PHCODE_LIVE_PREVIEW_QUERY_PARAM=PHCODE_LIVE_PREVIEW_QUERY_PARAM,exports.EVENT_SERVER_READY="SERVER_READY"});