Простой пример сеансов Sandbar или Ring в Google App Engine

#google-app-engine #clojure #compojure #ring #appengine-magic

#google-app-engine #clojure #compojure #ring #appengine-волшебство

Вопрос:

Я пытаюсь понять, как заставить сеансы и flash работать в Google App Engine. Может ли кто-нибудь привести наглядный пример использования Ring или Sandbar? Я думаю, что у меня работает sandbar, в частности, это не говорит мне об этом Var sandbar.stateful-session/sandbar-flash is unbound , и когда я сбрасываю обработчик, который я получаю, :flash и :session хотя я не уверен, является ли это сеансом sandbar или ring. Для полноты картины я упомяну, что я использую последние версии appengine — magic, ring, hiccup и sandbar. Похоже, что никаких несовместимостей или проблем нет.

Итак, наглядный пример, желательно с использованием flash-put!, flash-get, session-put! and session-get .

Ответ №1:

Обычно я не люблю отвечать на свои собственные вопросы, однако в этом случае я сделаю исключение, потому что:

a) Существует не так много простых для понимания примеров.

б) Было бы неплохо иметь быстрый рабочий пример для использования другими.

Примечание: магия appengine здесь не требуется, это также будет работать с обычными сеансами ring

Код

 ;; Place in a file called session.clj in the example project
(ns example.session
    "Works with the normal ring sessions 
     allowing you to use side-effects to manage them")

(declare current-session)

(defn wrap-session! [handler]
  (fn [request]
    (binding [current-session (atom (or (:session request) {}))]
      (let [response (handler request)]
        (assoc response :session @current-session)))))

(defn session-get
  ([k] (session-get k nil))
  ([k default] (if (vector? k)
                 (get-in @current-session k)
                 (get @current-session k default))))

(defn session-put!
  ([m]
     (swap! current-session (fn [a b] (merge a m)) m))
  ([k v]
     (swap! current-session (fn [a b] (merge a {k b})) v)))

(defn session-pop! [k]
  (let [res (get @current-session k)]
    (swap! current-session (fn [a b] (dissoc a b)) k)
    res))

(defn session-delete-key! [k]
  (swap! current-session (fn [a b] (dissoc a b)) k))

(defn session-destroy! []
  (swap! current-session (constantly nil)))


;; Place in a file called core.clj in the example project
(ns example.core
  (:use compojure.core
        [ring.middleware.keyword-params :only [wrap-keyword-params]]
        [ring.middleware.session :only [wrap-session]]
        [ring.middleware.session.cookie :only [cookie-store]]
        [example session])
  (:require [appengine-magic.core :as ae]))

(declare current-session)

(defroutes example-app-routes
  (GET "/" _
       (fn [req]
         (let [counter (session-get :counter 0)]
           {:status 200
            :headers {"Content-Type" "text/plain"}
            :body (str "started: " counter)})))
  (GET "/inc" _
       (fn [req]
         (let [counter (do 
                        (session-put! :counter (inc (session-get :counter 0)))
                        (session-get :counter))]
           {:status 200
            :headers {"Content-Type" "text/plain"}
            :body (str "incremented: " counter)}))))

(def example-app-handler
  (-> #'example-app-routes
      wrap-keyword-params
      wrap-session!
      (wrap-session {:cookie-name "example-app-session"
                     :store (cookie-store)})))

(ae/def-appengine-app example-app #'example-app-handler)
  

Как это использовать

Переход к http://127.0.0.1:8080/inc увеличивает счетчик в сеансе и http://127.0.0.1:8080 / отобразит значение counter в сеансе.

завершение сеанса! для работы сеансов не требуется, просто используйте

 (wrap-session {:cookie-name "example-app-session"
                     :store (cookie-store)})
  

предоставит вам рабочие функциональные сеансы. Однако я хотел управлять своими сеансами с побочными эффектами и завершением сеанса! предоставляет эту функциональность. Чтобы использовать функциональность, подобную flash, просто используйте session-put! чтобы ввести значение в сеанс, а затем использовать session-pop! чтобы удалить его.

Надеюсь, это полезно.

Ответ №2:

Если вы хотите использовать сеансы, предоставляемые GAE, вы можете использовать следующее

https://gist.github.com/1095841

включить сеанс, подобный ring, в ваши запросы, но на основе поддержки сеансов GAE.

Если вам нужны сеансы с отслеживанием состояния в дополнение к этому, вы можете использовать API сеансов с отслеживанием состояния, предоставляемый Sandbar

https://github.com/brentonashworth/sandbar