1 module hunt.http.server.LocalSessionStore; 2 3 import hunt.http.server.HttpSession; 4 import hunt.http.server.GlobalSettings; 5 6 import hunt.http.Exceptions; 7 import hunt.http.Util; 8 9 import hunt.collection.HashMap; 10 // import hunt.concurrency.Executors; 11 // import hunt.concurrency.Scheduler; 12 import hunt.concurrency.ScheduledThreadPoolExecutor; 13 import hunt.logging; 14 import hunt.util.AbstractLifecycle; 15 import hunt.util.Common; 16 import hunt.util.DateTime; 17 import hunt.util.Runnable; 18 19 import core.sync.mutex; 20 import core.time; 21 import std.range; 22 23 24 /** 25 * 26 */ 27 class LocalSessionStore : AbstractLifecycle, SessionStore { 28 29 private HashMap!(string, HttpSession) map; 30 private Mutex mapMutex; 31 private ScheduledThreadPoolExecutor executor; 32 // TODO: Tasks pending completion -@zhangxueping at 2019-10-23T11:21:26+08:00 33 // 34 // private final ConcurrentMap<string, HttpSession map = new ConcurrentHashMap<>(); 35 36 this() { 37 map = new HashMap!(string, HttpSession); 38 mapMutex = new Mutex(); 39 start(); 40 } 41 42 43 bool contains(string key) { 44 return map.containsKey(key); 45 } 46 47 48 override 49 bool remove(string key) { 50 if (!key.empty()) { 51 mapMutex.lock(); 52 scope(exit) mapMutex.unlock(); 53 54 map.remove(key); 55 } 56 return true; 57 } 58 59 override 60 bool put(string key, HttpSession value) { 61 if (!key.empty() && value !is null) { 62 if (!value.isNewSession()) { 63 value.setLastAccessedTime(DateTime.currentTimeMillis()); 64 } 65 mapMutex.lock(); 66 scope(exit) mapMutex.unlock(); 67 map.put(key, value); 68 } 69 return true; 70 } 71 72 override 73 HttpSession get(string key) { 74 if (key.empty()) { 75 throw new SessionNotFoundException(); 76 } 77 78 mapMutex.lock(); 79 scope(exit) mapMutex.unlock(); 80 HttpSession session = map.get(key); 81 if (session is null) { 82 throw new SessionNotFoundException(key); 83 } else { 84 if (!session.isValid()) { 85 map.remove(session.getId()); 86 throw new SessionInvalidException("the session is expired"); 87 } else { 88 session.setLastAccessedTime(DateTime.currentTimeMillis()); 89 session.setNewSession(false); 90 return session; 91 } 92 } 93 } 94 95 override 96 int size() { 97 return map.size(); 98 } 99 100 private void cleaup() { 101 mapMutex.lock(); 102 scope(exit) mapMutex.unlock(); 103 string[] ids; 104 foreach(string id, HttpSession session; map) { 105 if (!session.isValid()) { 106 ids ~= id; 107 } 108 } 109 110 if(ids.length>0) { 111 foreach(string id; ids) { 112 map.remove(id); 113 version(HUNT_DEBUG) tracef("remove expired session - %s", id); 114 } 115 116 version(HUNT_HTTP_DEBUG) infof("session size: %d", map.size()); 117 } 118 } 119 120 override 121 protected void initialize() { 122 executor = CommonUtil.scheduler(); 123 executor.setRemoveOnCancelPolicy(true); 124 executor.scheduleWithFixedDelay(new class Runnable { 125 void run() { 126 cleaup(); 127 } 128 }, 129 seconds(1), seconds(1)); 130 } 131 132 override 133 protected void destroy() { 134 // if (executor !is null) { 135 // executor.shutdown(); 136 // } 137 } 138 }