diff --git a/Package.swift b/Package.swift index cd38657..cb3ac47 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ let package = Package( .package(url: "https://github.com/Macro-swift/Macro.git", from: "1.0.2"), .package(url: "https://github.com/AlwaysRightInstitute/mustache.git", - from: "1.0.1") + from: "1.0.2") ], targets: [ @@ -44,7 +44,8 @@ let package = Package( .product(name: "MacroCore", package: "Macro"), .product(name: "fs", package: "Macro"), .product(name: "http", package: "Macro"), - "connect", "mime", "mustache" + "connect", "mime", + .product(name: "Mustache", package: "Mustache") ], exclude: [ "README.md" ]), .target(name: "MacroExpress", dependencies: [ .product(name: "MacroCore", package: "Macro"), diff --git a/Sources/connect/Session.swift b/Sources/connect/Session.swift index 11fdd65..be38516 100644 --- a/Sources/connect/Session.swift +++ b/Sources/connect/Session.swift @@ -11,6 +11,7 @@ import protocol MacroCore.EnvironmentKey import class http.IncomingMessage import class http.ServerResponse import struct Foundation.UUID +import struct NIOConcurrencyHelpers.NIOLock fileprivate let sessionIdCookie = Cookie(name: "NzSID", maxAge: 3600) @@ -42,17 +43,19 @@ public func session(store s : SessionStore = InMemorySessionStore(), return next() } + // TODO: This should do a session-checkout. // retrieve from store s.get(sessionID: sessionID) { err, session in - guard err == nil else { - console.log("could not retrieve session with ID \(sessionID): \(err!)") + if let rerr = err { + req.log + .notice("could not retrieve session with ID \(sessionID): \(rerr)") ctx.configureNewSession() return next() } guard let rsession = session else { - console.log("No error, but could not retrieve session with ID" + - " \(sessionID)") + req.log.notice( + "No error, but could not retrieve session with ID \(sessionID)") ctx.configureNewSession() return next() } @@ -61,9 +64,10 @@ public func session(store s : SessionStore = InMemorySessionStore(), req.environment[SessionKey.self] = rsession ctx.pushSessionCookie() _ = res.onceFinish { + // TODO: This should do the session-checkin. s.set(sessionID: sessionID, session: req.session) { err in if let err = err { - console.error("could not save session \(sessionID): \(err)") + req.log.error("could not save session \(sessionID): \(err)") } } } @@ -122,7 +126,7 @@ class SessionContext { _ = res.onceFinish { store.set(sessionID: newSessionID, session: req.session) { err in if let err = err { - console.error("could not save new session \(newSessionID): \(err)") + req.log.error("could not save new session \(newSessionID): \(err)") } } } @@ -140,20 +144,24 @@ public class Session { // // req.session["a"] = 10 // - // Think about it, kinda non-obvious ;-) + // kinda non-obvious. + // This should not be concurrent but use a checkin/checkout system. + fileprivate let lock = NIOLock() public var values = Dictionary() public subscript(key: String) -> Any? { set { - if let v = newValue { values[key] = v } - else { values.removeValue(forKey: key) } + lock.withLock { + if let v = newValue { values[key] = v } + else { _ = values.removeValue(forKey: key) } + } } - get { return values[key] } + get { return lock.withLock { values[key] } } } public subscript(int key: String) -> Int { - guard let v = values[key] else { return 0 } + guard let v = lock.withLock({ values[key] }) else { return 0 } if let iv = v as? Int { return iv } #if swift(>=5.10) if let i = (v as? any BinaryInteger) { return Int(i) } @@ -228,6 +236,8 @@ public extension SessionStore { public class InMemorySessionStore : SessionStore { + // Well, there should be a checkout/checkin system?! + fileprivate let lock = NIOLock() var store : [ String : Session ] public init() { @@ -235,7 +245,7 @@ public class InMemorySessionStore : SessionStore { } public func get(sessionID sid: String, _ cb: ( Error?, Session? ) -> Void ) { - guard let session = store[sid] else { + guard let session = lock.withLock({ store[sid] }) else { cb(SessionStoreError.SessionNotFound, nil) return } @@ -245,7 +255,7 @@ public class InMemorySessionStore : SessionStore { public func set(sessionID sid: String, session: Session, _ cb: ( Error? ) -> Void ) { - store[sid] = session + lock.withLock { store[sid] = session } cb(nil) } @@ -256,21 +266,21 @@ public class InMemorySessionStore : SessionStore { } public func destroy(sessionID sid: String, _ cb: ( String ) -> Void) { - store.removeValue(forKey: sid) + lock.withLock { _ = store.removeValue(forKey: sid) } cb(sid) } public func clear(cb: ( Error? ) -> Void ) { - store.removeAll() + lock.withLock { store.removeAll() } cb(nil) } public func length(cb: ( Error?, Int) -> Void) { - cb(nil, store.count) + cb(nil, lock.withLock { store.count }) } public func all(cb: ( Error?, [ Session ] ) -> Void) { - let values = Array(store.values) + let values = Array(lock.withLock { store.values }) cb(nil, values) } } diff --git a/Sources/express/Mustache.swift b/Sources/express/Mustache.swift index 35cbd56..acff6d9 100644 --- a/Sources/express/Mustache.swift +++ b/Sources/express/Mustache.swift @@ -3,14 +3,14 @@ // Noze.io / Macro // // Created by Helge Heß on 02/06/16. -// Copyright © 2016-2020 ZeeZide GmbH. All rights reserved. +// Copyright © 2016-2024 ZeeZide GmbH. All rights reserved. // import func fs.readFile import func fs.readFileSync import enum fs.path import let MacroCore.console -import mustache +import Mustache let mustacheExpress : ExpressEngine = { path, options, done in fs.readFile(path, "utf8") { err, str in @@ -25,7 +25,7 @@ let mustacheExpress : ExpressEngine = { path, options, done in return } - let parser = MustacheParser() + var parser = MustacheParser() let tree = parser.parse(string: template) let ctx = ExpressMustacheContext(path: path, object: options) @@ -53,7 +53,7 @@ class ExpressMustacheContext : MustacheDefaultRenderingContext { return nil } - let parser = MustacheParser() + var parser = MustacheParser() let tree = parser.parse(string: template) return tree }