|
| 1 | +; modified from https://github.com/gcv/appengine-magic under MIT License |
| 2 | +; |
| 3 | +; Copyright (c) 2010 Constantine Vetoshev |
| 4 | +; |
| 5 | +;Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 6 | +;this software and associated documentation files (the "Software"), to deal in |
| 7 | +;the Software without restriction, including without limitation the rights to |
| 8 | +;use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| 9 | +;the Software, and to permit persons to whom the Software is furnished to do so, |
| 10 | +;subject to the following conditions: |
| 11 | +; |
| 12 | +;The above copyright notice and this permission notice shall be included in all |
| 13 | +;copies or substantial portions of the Software. |
| 14 | +; |
| 15 | +;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | +;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
| 17 | +;FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
| 18 | +;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| 19 | +;IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 20 | +;CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 21 | + |
| 22 | + |
| 23 | +(in-ns 'appengine-magic.core) |
| 24 | + |
| 25 | +(use 'appengine-magic.local-env-helpers |
| 26 | + '[appengine-magic.servlet :only [servlet]] |
| 27 | + '[appengine-magic.swank :only [wrap-swank]] |
| 28 | + '[ring.middleware.file :only [wrap-file]] |
| 29 | + '[ring.middleware.file-info :only [wrap-file-info]]) |
| 30 | + |
| 31 | +(require '[clojure.string :as str] |
| 32 | + '[appengine-magic.jetty :as jetty] |
| 33 | + '[appengine-magic.blobstore-upload :as blobstore-upload]) |
| 34 | + |
| 35 | +(import java.io.File |
| 36 | + com.google.apphosting.api.ApiProxy) |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | +;;; ---------------------------------------------------------------------------- |
| 41 | +;;; appengine-magic core API functions |
| 42 | +;;; ---------------------------------------------------------------------------- |
| 43 | + |
| 44 | +(defn default-war-root [] |
| 45 | + (-> (clojure.lang.RT/baseLoader) |
| 46 | + (.getResource ".") |
| 47 | + .getFile |
| 48 | + java.net.URLDecoder/decode |
| 49 | + (File. "../war") |
| 50 | + .getAbsolutePath)) |
| 51 | + |
| 52 | + |
| 53 | +(defn appengine-base-url [& {:keys [https?] :or {https? false}}] |
| 54 | + ;; NB: The https? argument is intentionally ignored. HTTPS is not supported |
| 55 | + ;; for local environments. |
| 56 | + (str "http://localhost:" |
| 57 | + (str @appengine-magic.local-env-helpers/*current-server-port*))) |
| 58 | + |
| 59 | + |
| 60 | +(defn wrap-war-static [app, #^String war-root] |
| 61 | + (fn [req] |
| 62 | + (let [#^String uri (:uri req)] |
| 63 | + (if (.startsWith uri "/WEB-INF") |
| 64 | + (app req) |
| 65 | + ((wrap-file-info (wrap-file app war-root)) req))))) |
| 66 | + |
| 67 | + |
| 68 | +(defmacro def-appengine-app [app-var-name handler & {:keys [war-root]}] |
| 69 | + `(def ~app-var-name |
| 70 | + (let [handler# ~handler |
| 71 | + war-root-arg# ~war-root |
| 72 | + war-root# (if (nil? war-root-arg#) |
| 73 | + (default-war-root) |
| 74 | + war-root-arg#)] |
| 75 | + {:handler (-> handler# |
| 76 | + wrap-swank |
| 77 | + (wrap-war-static war-root#)) |
| 78 | + :war-root war-root#}))) |
| 79 | + |
| 80 | + |
| 81 | +(defn make-appengine-request-environment-filter [] |
| 82 | + (reify javax.servlet.Filter |
| 83 | + (init [_ filter-config] |
| 84 | + (.setAttribute (.getServletContext filter-config) |
| 85 | + "com.google.appengine.devappserver.ApiProxyLocal" |
| 86 | + (ApiProxy/getDelegate))) |
| 87 | + (destroy [_]) |
| 88 | + (doFilter [_ req resp chain] |
| 89 | + (let [all-cookies (.getCookies req) |
| 90 | + login-cookie (when all-cookies |
| 91 | + (let [raw (first (filter #(= "dev_appserver_login" (.getName %)) |
| 92 | + (.getCookies req)))] |
| 93 | + (when raw (.getValue raw)))) |
| 94 | + [user-email user-admin? _] (when login-cookie |
| 95 | + (str/split login-cookie #":")) |
| 96 | + thread-environment-proxy (make-thread-environment-proxy :user-email user-email |
| 97 | + :user-admin? user-admin?)] |
| 98 | + (ApiProxy/setEnvironmentForCurrentThread thread-environment-proxy)) |
| 99 | + (.doFilter chain req resp)))) |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | +;;; ---------------------------------------------------------------------------- |
| 104 | +;;; development server controls |
| 105 | +;;; ---------------------------------------------------------------------------- |
| 106 | + |
| 107 | +(defonce ^{:dynamic true} *server* (atom nil)) |
| 108 | + |
| 109 | + |
| 110 | +(defn start [appengine-app & {:keys [port join? high-replication in-memory] |
| 111 | + :or {port 8080, join? false, high-replication false, in-memory false}}] |
| 112 | + (let [war-root (java.io.File. (:war-root appengine-app)) |
| 113 | + handler-servlet (servlet (:handler appengine-app))] |
| 114 | + (appengine-init war-root port high-replication in-memory) |
| 115 | + (reset! |
| 116 | + *server* |
| 117 | + (jetty/start |
| 118 | + {"/*" [(make-appengine-request-environment-filter) |
| 119 | + (com.google.apphosting.utils.servlet.TransactionCleanupFilter.) |
| 120 | + (com.google.appengine.api.blobstore.dev.ServeBlobFilter.)]} |
| 121 | + {"/" handler-servlet |
| 122 | + ;; These mappings are from webdefault.xml in appengine-local-runtime-*.jar. |
| 123 | + "/_ah/admin" (com.google.apphosting.utils.servlet.DatastoreViewerServlet.) |
| 124 | + "/_ah/admin/backends" (com.google.apphosting.utils.servlet.ServersServlet.) |
| 125 | + "/_ah/admin/capabilitiesstatus" (com.google.apphosting.utils.servlet.CapabilitiesStatusServlet.) |
| 126 | + "/_ah/admin/datastore" (com.google.apphosting.utils.servlet.DatastoreViewerServlet.) |
| 127 | + "/_ah/admin/inboundmail" (com.google.apphosting.utils.servlet.InboundMailServlet.) |
| 128 | + "/_ah/admin/search" (com.google.apphosting.utils.servlet.SearchServlet.) |
| 129 | + "/_ah/admin/taskqueue" (com.google.apphosting.utils.servlet.TaskQueueViewerServlet.) |
| 130 | + "/_ah/admin/xmpp" (com.google.apphosting.utils.servlet.XmppServlet.) |
| 131 | + "/_ah/adminConsole" (org.apache.jsp.ah.adminConsole_jsp.) |
| 132 | + "/_ah/backendsBody" (org.apache.jsp.ah.backendsBody_jsp.) |
| 133 | + "/_ah/backendsFinal" (org.apache.jsp.ah.backendsFinal_jsp.) |
| 134 | + "/_ah/backendsHead" (org.apache.jsp.ah.backendsHead_jsp.) |
| 135 | + "/_ah/blobImage" (com.google.appengine.api.images.dev.LocalBlobImageServlet.) |
| 136 | + "/_ah/blobUpload" (com.google.appengine.api.blobstore.dev.UploadBlobServlet.) |
| 137 | + "/_ah/capabilitiesStatusBody" (org.apache.jsp.ah.capabilitiesStatusBody_jsp.) |
| 138 | + "/_ah/capabilitiesStatusFinal" (org.apache.jsp.ah.capabilitiesStatusFinal_jsp.) |
| 139 | + "/_ah/capabilitiesStatusHead" (org.apache.jsp.ah.capabilitiesStatusHead_jsp.) |
| 140 | + "/_ah/capabilitiesViewer" (com.google.apphosting.utils.servlet.CapabilitiesStatusServlet.) |
| 141 | + "/_ah/channel/jsapi" (com.google.appengine.api.channel.dev.ServeScriptServlet.) |
| 142 | + "/_ah/channelLocalChannel" (com.google.appengine.api.channel.dev.LocalChannelServlet.) |
| 143 | + "/_ah/datastoreViewer" (com.google.apphosting.utils.servlet.DatastoreViewerServlet.) |
| 144 | + "/_ah/datastoreViewerBody" (org.apache.jsp.ah.datastoreViewerBody_jsp.) |
| 145 | + "/_ah/datastoreViewerFinal" (org.apache.jsp.ah.datastoreViewerFinal_jsp.) |
| 146 | + "/_ah/datastoreViewerHead" (org.apache.jsp.ah.datastoreViewerHead_jsp.) |
| 147 | + "/_ah/entityDetailsBody" (org.apache.jsp.ah.entityDetailsBody_jsp.) |
| 148 | + "/_ah/entityDetailsFinal" (org.apache.jsp.ah.entityDetailsFinal_jsp.) |
| 149 | + "/_ah/entityDetailsHead" (org.apache.jsp.ah.entityDetailsHead_jsp.) |
| 150 | + "/_ah/inboundmailBody" (org.apache.jsp.ah.inboundMailBody_jsp.) |
| 151 | + "/_ah/inboundmailFinal" (org.apache.jsp.ah.inboundMailFinal_jsp.) |
| 152 | + "/_ah/inboundmailHead" (org.apache.jsp.ah.inboundMailHead_jsp.) |
| 153 | + "/_ah/indexDetailsBody" (org.apache.jsp.ah.indexDetailsBody_jsp.) |
| 154 | + "/_ah/indexDetailsFinal" (org.apache.jsp.ah.indexDetailsFinal_jsp.) |
| 155 | + "/_ah/indexDetailsHead" (org.apache.jsp.ah.indexDetailsHead_jsp.) |
| 156 | + "/_ah/login" (com.google.appengine.api.users.dev.LocalLoginServlet.) |
| 157 | + "/_ah/logout" (com.google.appengine.api.users.dev.LocalLogoutServlet.) |
| 158 | + "/_ah/oauthAuthorizeToken" (com.google.appengine.api.users.dev.LocalOAuthAuthorizeTokenServlet.) |
| 159 | + "/_ah/oauthGetAccessToken" (com.google.appengine.api.users.dev.LocalOAuthAccessTokenServlet.) |
| 160 | + "/_ah/oauthGetRequestToken" (com.google.appengine.api.users.dev.LocalOAuthRequestTokenServlet.) |
| 161 | + "/_ah/queue_deferred" (com.google.apphosting.utils.servlet.DeferredTaskServlet.) |
| 162 | + "/_ah/resources" (com.google.apphosting.utils.servlet.AdminConsoleResourceServlet.) |
| 163 | + "/_ah/searchDocumentBody" (org.apache.jsp.ah.searchDocumentBody_jsp.) |
| 164 | + "/_ah/searchDocumentFinal" (org.apache.jsp.ah.searchDocumentFinal_jsp.) |
| 165 | + "/_ah/searchDocumentHead" (org.apache.jsp.ah.searchDocumentHead_jsp.) |
| 166 | + "/_ah/searchIndexBody" (org.apache.jsp.ah.searchIndexBody_jsp.) |
| 167 | + "/_ah/searchIndexFinal" (org.apache.jsp.ah.searchIndexFinal_jsp.) |
| 168 | + "/_ah/searchIndexHead" (org.apache.jsp.ah.searchIndexHead_jsp.) |
| 169 | + "/_ah/searchIndexesListBody" (org.apache.jsp.ah.searchIndexesListBody_jsp.) |
| 170 | + "/_ah/searchIndexesListFinal" (org.apache.jsp.ah.searchIndexesListFinal_jsp.) |
| 171 | + "/_ah/searchIndexesListHead" (org.apache.jsp.ah.searchIndexesListHead_jsp.) |
| 172 | + "/_ah/sessioncleanup" (com.google.apphosting.utils.servlet.SessionCleanupServlet.) |
| 173 | + "/_ah/taskqueueViewerBody" (org.apache.jsp.ah.taskqueueViewerBody_jsp.) |
| 174 | + "/_ah/taskqueueViewerFinal" (org.apache.jsp.ah.taskqueueViewerFinal_jsp.) |
| 175 | + "/_ah/taskqueueViewerHead" (org.apache.jsp.ah.taskqueueViewerHead_jsp.) |
| 176 | + "/_ah/upload/*" (servlet (blobstore-upload/make-blob-upload-handler war-root)) |
| 177 | + "/_ah/xmppBody" (org.apache.jsp.ah.xmppBody_jsp.) |
| 178 | + "/_ah/xmppFinal" (org.apache.jsp.ah.xmppFinal_jsp.) |
| 179 | + "/_ah/xmppHead" (org.apache.jsp.ah.xmppHead_jsp.)} |
| 180 | + :port port |
| 181 | + :join? join?)))) |
| 182 | + |
| 183 | + |
| 184 | +(defn stop [] |
| 185 | + (when-not (nil? @*server*) |
| 186 | + (appengine-clear) |
| 187 | + (jetty/stop @*server*) |
| 188 | + (reset! *server* nil))) |
| 189 | + |
| 190 | + |
| 191 | +(defn serve [appengine-app & {:keys [port high-replication in-memory] |
| 192 | + :or {port 8080, high-replication false, in-memory false}}] |
| 193 | + (stop) |
| 194 | + (start appengine-app :port port :high-replication high-replication :in-memory in-memory)) |
0 commit comments