zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

ets.ex (2375B)


      1 defmodule Plug.Session.ETS do
      2   @moduledoc """
      3   Stores the session in an in-memory ETS table.
      4 
      5   This store does not create the ETS table; it expects that an
      6   existing named table with public properties is passed as an
      7   argument.
      8 
      9   We don't recommend using this store in production as every
     10   session will be stored in ETS and never cleaned until you
     11   create a task responsible for cleaning up old entries.
     12 
     13   Also, since the store is in-memory, it means sessions are
     14   not shared between servers. If you deploy to more than one
     15   machine, using this store is again not recommended.
     16 
     17   This store, however, can be used as an example for creating
     18   custom storages, based on Redis, Memcached, or a database
     19   itself.
     20 
     21   ## Options
     22 
     23     * `:table` - ETS table name (required)
     24 
     25   For more information on ETS tables, visit the Erlang documentation at
     26   http://www.erlang.org/doc/man/ets.html.
     27 
     28   ## Storage
     29 
     30   The data is stored in ETS in the following format:
     31 
     32       {sid :: String.t, data :: map, timestamp :: :erlang.timestamp}
     33 
     34   The timestamp is updated whenever there is a read or write to the
     35   table and it may be used to detect if a session is still active.
     36 
     37   ## Examples
     38 
     39       # Create an ETS table when the application starts
     40       :ets.new(:session, [:named_table, :public, read_concurrency: true])
     41 
     42       # Use the session plug with the table name
     43       plug Plug.Session, store: :ets, key: "sid", table: :session
     44 
     45   """
     46 
     47   @behaviour Plug.Session.Store
     48 
     49   @max_tries 100
     50 
     51   @impl true
     52   def init(opts) do
     53     Keyword.fetch!(opts, :table)
     54   end
     55 
     56   @impl true
     57   def get(_conn, sid, table) do
     58     case :ets.lookup(table, sid) do
     59       [{^sid, data, _timestamp}] ->
     60         :ets.update_element(table, sid, {3, now()})
     61         {sid, data}
     62 
     63       [] ->
     64         {nil, %{}}
     65     end
     66   end
     67 
     68   @impl true
     69   def put(_conn, nil, data, table) do
     70     put_new(data, table)
     71   end
     72 
     73   def put(_conn, sid, data, table) do
     74     :ets.insert(table, {sid, data, now()})
     75     sid
     76   end
     77 
     78   @impl true
     79   def delete(_conn, sid, table) do
     80     :ets.delete(table, sid)
     81     :ok
     82   end
     83 
     84   defp put_new(data, table, counter \\ 0)
     85        when counter < @max_tries do
     86     sid = Base.encode64(:crypto.strong_rand_bytes(96))
     87 
     88     if :ets.insert_new(table, {sid, data, now()}) do
     89       sid
     90     else
     91       put_new(data, table, counter + 1)
     92     end
     93   end
     94 
     95   defp now() do
     96     :os.timestamp()
     97   end
     98 end