root/HTTP/Token.lua

Revision 1368 (checked in by rsz, 6 months ago)

cleanup

Line 
1 --------------------------------------------------------------------------------
2 -- Title:               Token.lua
3 -- Description:         Like a square peg in a round hole
4 -- Author:              Raphaël Szwarc http://alt.textdrive.com/lua/
5 -- Creation Date:       January 30, 2007
6 -- Legal:               Copyright (C) 2007 Raphaël Szwarc
7 --                      Under the terms of the MIT License
8 --                      http://www.opensource.org/licenses/mit-license.html
9 --------------------------------------------------------------------------------
10
11 -- import dependencies
12 local crypto = require( 'crypto' )
13 local math = require( 'math' )
14 local os = require( 'os' )
15 local package = require( 'package' )
16 local string = require( 'string' )
17
18 local getmetatable = getmetatable
19 local rawset = rawset
20 local setmetatable = setmetatable
21 local tostring = tostring
22
23 local version = _VERSION
24
25 --------------------------------------------------------------------------------
26 -- Token
27 --------------------------------------------------------------------------------
28
29 module( 'Token' )
30 _VERSION = '1.0'
31
32 local self = setmetatable( _M, {} )
33 local meta = getmetatable( self )
34
35 --------------------------------------------------------------------------------
36 -- Utilities
37 --------------------------------------------------------------------------------
38
39 local context = setmetatable( {}, { __mode = 'k' } )
40
41 local function Base( aTime )
42     local aTime = aTime or os.time()
43     local aDate = os.date( '*t', aTime )
44     local aDateFormat = os.date( '!%A, %B %d %Y, %p %Z ', aTime )
45     local aBase = crypto.sha1( ( '%s %s %s' ):format( aDateFormat, package.path, version ) )
46    
47     aDate = { year = aDate.year, month = aDate.month, day = aDate.day }
48     aTime = os.time( aDate )
49    
50     return aBase, aTime
51 end
52
53 local function Range( aContext )
54     local aRandom = aContext.random
55     local aLength = aRandom( 3, 9 )
56     local aStart = aRandom( 1, 40 - aLength )
57     local anEnd = aStart + aLength - 1
58    
59     return aStart, anEnd
60 end
61
62 local function Convert( aValue, anIndex )
63     return string.char( 103 + aValue + anIndex )
64 end
65
66 local function ID( aContext )
67     local aPrefix = aContext.prefix
68     local aBase = aContext.base
69     local aRandom = aContext.random
70     local aSuffix = crypto.sha1( tostring( aRandom() ) )
71     local anID = ( '%s %s %s' ):format( aPrefix, aBase, aSuffix )
72    
73     anID = crypto.sha1( anID )
74     anID = anID:sub( Range( aContext ) )
75     anID = anID:gsub( '(%d)()', Convert ):lower()
76    
77     if not aContext[ anID ] then
78         aContext[ anID ] = true
79        
80         return anID
81     end
82    
83     return ID( aContext )
84 end
85
86 local function Random( aSeed )
87     math.randomseed( aSeed )
88
89     return math.random
90 end
91
92 --------------------------------------------------------------------------------
93 -- Metamethods
94 --------------------------------------------------------------------------------
95
96 function meta:__call( aPrefix, aTime )
97     local aPrefix = crypto.sha1( tostring( aPrefix ) )
98     local aBase, aSeed = Base( aTime )
99     local aRandom = Random( aSeed )
100     local aContext = { prefix = aPrefix, base = aBase, random = aRandom }
101     local aToken = {}
102    
103     setmetatable( aToken, self )
104     context[ aToken ] = aContext
105    
106     return aToken
107 end
108
109 function meta:__concat( aValue )
110     return tostring( self ) .. tostring( aValue )
111 end
112
113 function meta:__tostring()
114     return ( '%s/%s' ):format( self._NAME, self._VERSION )
115 end
116
117 function self:__call()
118     return ID( context[ self ] )
119 end
120
121 function self:__index( aKey )
122     local anID = self()
123    
124     rawset( self, aKey, anID )
125    
126     return anID
127 end
Note: See TracBrowser for help on using the browser.