You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
9.7 KiB
222 lines
9.7 KiB
--===========================================================================--
|
|
-- --
|
|
-- System.Context --
|
|
-- --
|
|
--===========================================================================--
|
|
|
|
--===========================================================================--
|
|
-- Author : kurapica125@outlook.com --
|
|
-- URL : http://github.com/kurapica/PLoop --
|
|
-- Create Date : 2020/08/18 --
|
|
-- Update Date : 2020/08/27 --
|
|
-- Version : 1.0.2 --
|
|
--===========================================================================--
|
|
|
|
PLoop(function(_ENV)
|
|
namespace "System.Context"
|
|
|
|
--- Represents the session item storage provider, normally a single object works for all sessions
|
|
__Sealed__() interface "ISessionStorageProvider" (function(_ENV)
|
|
|
|
-----------------------------------------------------------------------
|
|
-- property --
|
|
-----------------------------------------------------------------------
|
|
--- Whether update the time out of the session when accessed
|
|
__Abstract__() property "KeepAlive" { type = Boolean }
|
|
|
|
--- The minute count before session time out, this will be used if the session's timeout is not set
|
|
__Abstract__() property "TimeoutMinutes"{ type = Number, default = 30 }
|
|
|
|
-----------------------------------------------------------------------
|
|
-- method --
|
|
-----------------------------------------------------------------------
|
|
--- Whether the session ID existed in the storage.
|
|
__Abstract__() function Contains(self, id) end
|
|
|
|
--- Get session item
|
|
__Abstract__() function GetItems(self, id) end
|
|
|
|
--- Remove session item
|
|
__Abstract__() function RemoveItems(self, id) end
|
|
|
|
--- Try sets the item with an un-existed key, return true if success, this should be a mutex operation
|
|
__Abstract__() function TrySetItems(self, id, time, timeout) end
|
|
|
|
--- Update the item with current session data
|
|
__Abstract__() function SetItems(self, id, item, timeout) end
|
|
|
|
--- Update the item's timeout
|
|
__Abstract__() function ResetItems(self, id, timeout) end
|
|
end)
|
|
|
|
--- Represents the session to be used in the Context
|
|
__Sealed__() class "Session" (function(_ENV)
|
|
|
|
export { Date }
|
|
|
|
-----------------------------------------------------------------------
|
|
-- method --
|
|
-----------------------------------------------------------------------
|
|
--- Save the session items
|
|
function SaveSessionItems(self)
|
|
local provider = self.SessionStorageProvider
|
|
local sessionID = self.SessionID
|
|
if not (provider and sessionID) then return end
|
|
|
|
if self.Canceled then
|
|
-- Clear the session items
|
|
return provider:RemoveItems(sessionID)
|
|
elseif self.IsNewSession or self.ItemsChanged then
|
|
-- Set teh session items
|
|
return provider:SetItems(sessionID, self.RawItems, self.Timeout or Date.Now:AddMinutes(provider.TimeoutMinutes))
|
|
elseif self.TimeoutChanged then
|
|
-- Reset the timeout with the settings
|
|
return provider:ResetItems(sessionID, self.Timeout)
|
|
elseif provider.KeepAlive then
|
|
-- Keep the session alive
|
|
return provider:ResetItems(sessionID, Date.Now:AddMinutes(provider.TimeoutMinutes))
|
|
end
|
|
end
|
|
|
|
--- Load the Session Items
|
|
function LoadSessionItems(self)
|
|
local items
|
|
if self.SessionID and self.SessionStorageProvider then
|
|
-- Load the session items
|
|
items = self.SessionStorageProvider:GetItems(self.SessionID)
|
|
end
|
|
|
|
self.IsNewSession = not items
|
|
items = items or {}
|
|
|
|
self.RawItems = items
|
|
return items
|
|
end
|
|
|
|
-----------------------------------------------------------------------
|
|
-- property --
|
|
-----------------------------------------------------------------------
|
|
--- Gets the unique identifier for the session
|
|
__Abstract__() property "SessionID" { type = Any, handler = function(self) self.RawItems, self.IsNewSession, self.ItemsChanged = nil, false, false end }
|
|
|
|
--- The context
|
|
__Abstract__() property "Context" { type = Context }
|
|
|
|
--- The Session Storage Provider, this should be provided by the session class
|
|
__Abstract__() property "SessionStorageProvider" { type = ISessionStorageProvider }
|
|
|
|
--- Gets or sets the session items
|
|
__Indexer__()
|
|
__Abstract__() property "Items" {
|
|
set = function(self, key, value)
|
|
if self.RawItems[key] ~= value then
|
|
self.ItemsChanged = true
|
|
self.RawItems[key] = value
|
|
end
|
|
end,
|
|
get = function(self, key) return self.RawItems[key] end,
|
|
}
|
|
|
|
--- The raw item table to be used for serialization
|
|
__Abstract__() property "RawItems" { default = LoadSessionItems }
|
|
|
|
--- Gets or sets the date time, allowed the next request access the session
|
|
__Set__(PropertySet.Clone)
|
|
__Abstract__() property "Timeout" { type = Date, handler = function(self) self.TimeoutChanged = true end }
|
|
|
|
--- Whether the time out is changed
|
|
__Abstract__() property "TimeoutChanged"{ type = Boolean, default = false }
|
|
|
|
--- Whether the current session is canceled
|
|
__Abstract__() property "Canceled" { type = Boolean, default = false }
|
|
|
|
--- Gets a value indicating whether the session was newly created
|
|
__Abstract__() property "IsNewSession" { type = Boolean, default = false }
|
|
|
|
--- Whether the session items has changed
|
|
__Abstract__() property "ItemsChanged" { type = Boolean, default = false }
|
|
|
|
-----------------------------------------------------------------------
|
|
-- constructor --
|
|
-----------------------------------------------------------------------
|
|
__Abstract__() __Arguments__{ Context/nil, ISessionStorageProvider/nil }
|
|
function __ctor(self, context, provider)
|
|
self.Context = context
|
|
self.SessionStorageProvider = provider
|
|
end
|
|
end)
|
|
|
|
--- A test session storage provider based on the Lua table
|
|
__Sealed__() class "TableSessionStorageProvider" (function (_ENV)
|
|
extend "ISessionStorageProvider"
|
|
|
|
export {
|
|
ostime = _G.os and os.time or _G.time,
|
|
pairs = pairs,
|
|
}
|
|
|
|
-----------------------------------------------------------------------
|
|
-- inherit method --
|
|
-----------------------------------------------------------------------
|
|
function Contains(self, id)
|
|
return self.Storage[id] and true or false
|
|
end
|
|
|
|
function GetItems(self, id)
|
|
local item = self.Storage[id]
|
|
if item then
|
|
local timeout = self.Timeout[id]
|
|
if timeout and timeout.Time < ostime() then
|
|
self:RemoveItem(id)
|
|
else
|
|
return item
|
|
end
|
|
end
|
|
end
|
|
|
|
function RemoveItems(self, id)
|
|
self.Storage[id] = nil
|
|
self.Timeout[id] = nil
|
|
end
|
|
|
|
function SetItems(self, id, item, timeout)
|
|
self.Storage[id] = item
|
|
if timeout then
|
|
self.Timeout[id]= timeout
|
|
end
|
|
end
|
|
|
|
function ResetItems(self, id, timeout)
|
|
if timeout and self.Storage[id] then
|
|
self.Timeout[id]= timeout
|
|
end
|
|
end
|
|
|
|
function TrySetItems(self, id, time, timeout)
|
|
if self.Storage[id] ~= nil then return false end
|
|
self:SetItems(id, time, timeout)
|
|
return true
|
|
end
|
|
|
|
-----------------------------------------------------------------------
|
|
-- property --
|
|
-----------------------------------------------------------------------
|
|
property "Storage" { type = Table, default = Toolset.newtable }
|
|
property "Timeout" { type = Table, default = Toolset.newtable }
|
|
|
|
-----------------------------------------------------------------------
|
|
-- method --
|
|
-----------------------------------------------------------------------
|
|
function ClearTimeoutItems(self)
|
|
local storage = self.Storage
|
|
local timeouts = self.Timeout
|
|
local now = ostime()
|
|
for id in pairs(storage) do
|
|
if timeouts[id] and timeouts[id].Time < now then
|
|
storage[id] = nil
|
|
timeouts[id]= nil
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
end)
|
|
|