don't stop believing

Perfect로 redis에 연결해 봅시다. 1 본문

Swift/Perfect

Perfect로 redis에 연결해 봅시다. 1

Tongchun 2018. 1. 17. 17:56

Perfect의 Perfect-Session-Redis-Demo를 참고하여 Redis와 Session 사용에 대해 확인해 보겠습니다.

https://github.com/PerfectExamples/Perfect-Session-Redis-Demo


Perfect Redis: https://github.com/PerfectlySoft/Perfect-Redis

Perfect Session: https://perfect.org/docs/sessions.html


Remind 차원에서 처음부터 차근차근 시작해 보겠습니다.

먼저 swift 버전을 확인해 봅시다.

1
2
3
$ swift --version
Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)
Target: x86_64-apple-macosx10.9
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

개발 환경은 Mac OS입니다.

Terminal에서 프로젝트 폴더를 만들고 swift package를 초기화 해줍니다.

1
2
3
$ mkdir nGleServer005
$ cd nGleServer005
$ swift package init --type executable
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Package.swift 파일과 몇 개의 폴더가 생성됩니다.

바로 xCode project로 변환해 xcode로 프로젝트를 열어 줍니다.

1
2
$ swift package generate-xcodeproj
$ open nGleServer005.xcodeproj
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

xCode에서 Package.swift파일을 열고 dependencies에 Perfect-HTTPServerPerfect-Session-Redis를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "nGleServer005",
dependencies: [
.package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0"),
.package(url: "https://github.com/PerfectlySoft/Perfect-Session-Redis.git", from: "3.0.0"),
],
targets: [
.target(
name: "nGleServer005",
dependencies: ["PerfectHTTPServer", "PerfectSessionRedis"]),
]
)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

swift 3.0일때와 크게 달라진 부분은 dependencies에 추가 후 targets의 dependencies에도 import되는 package를 추가해야 합니다. 그렇지 않으면 xcodeproj 변환 후 xCode에서 해당 package들이 등록되지 않습니다.

xcode에서 Package.swift파일을 저장하고 terminal에서 package update를 해줍니다.

1
$ swift package update
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

실행하면 github에 있는 package들이 clone되는 것을 확인할 수 있습니다.

swift 빌드도 해봅시다.

1
$ swift build
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

빌드가 정상적으로 되었다면 다시 xcodeproj로 변환하고 열어 줍니다.

1
2
$ swift package generate-xcodeproj
$ open nGleServer005.xcodeproj
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

xCode의 오른쪽 Target Membership창에 dependencies에 추가된 package들을 확인할 수 있습니다.

이제 파일을 추가합니다. main.swift가 있는 위치에 Routes.swift와 Handlers.swift 파일을 추가합니다.

Routes.swift 파일에는 PerfectHTTP의 routes를 정의하고 리턴하는 클레스를 작성할 예정입니다.

Handlers.swift 파일에는 각 route에 해당하는 method들을 작성할 예정입니다.

1
2
3
4
5
6
$ cd ./Sources/nGleServer005/
$ touch Routes.swift
$ touch Handlers.swift
$ cd ../..
$ swift package generate-xcodeproj
$ open nGleServer005.xcodeproj/
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

다시 xcodeproj로 변환하고 xcode에서 보면 파일이 추가된 것을 확인 할 수 있습니다.


main.swift에 다음과 같이 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import PerfectSession
import PerfectSessionRedis
import PerfectRedis
RedisSessionConnector.host = "192.168.0.188"
RedisSessionConnector.password = "ngleredis1234"
RedisSessionConnector.port = redisDefaultPort
let server = HTTPServer()
SessionConfig.name = "TestingRedisDrivers"
SessionConfig.idle = 60
// Optional
SessionConfig.cookieDomain = "localhost"
SessionConfig.IPAddressLock = true
SessionConfig.userAgentLock = true
SessionConfig.CSRF.checkState = true
SessionConfig.CORS.enabled = true
SessionConfig.CORS.acceptableHostnames.append("http://www.test-cors.org")
//SessionConfig.CORS.acceptableHostnames.append("*.test-cors.org")
SessionConfig.CORS.maxAge = 60
let sessionDriver = SessionRedisDriver()
server.setRequestFilters([sessionDriver.requestFilter])
server.setResponseFilters([sessionDriver.responseFilter])
server.addRoutes(nGle005Routes())
server.serverPort = 8181
do {
// Launch the HTTP server.
try server.start()
} catch PerfectError.networkError(let err, let msg) {
print("Network error thrown: \(err) \(msg)")
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Routes.swift 파일입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import PerfectLib
import PerfectHTTP
public func nGle005Routes() -> Routes {
var routes = Routes()
routes.add(method: .get, uri: "/", handler: WebHandlers.indexHandlerGet)
routes.add(method: .get, uri: "/json", handler: WebHandlers.indexHandlerGetJSON)
routes.add(method: .get, uri: "/nocsrf", handler: WebHandlers.formNoCSRF)
routes.add(method: .get, uri: "/withcsrf", handler: WebHandlers.formWithCSRF)
routes.add(method: .post, uris: ["/nocsrf", "/withcsrf"], handler: WebHandlers.formReceive)
// for CORS
routes.add(method: .get, uri: "/cors", handler: WebHandlers.CORSHandlerGet)
return routes
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Handler.swift 파일입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import PerfectLib
import PerfectHTTP
import PerfectSession
import PerfectSessionRedis
import PerfectRedis
public class WebHandlers {
/* =================================================================================================================
Index
================================================================================================================= */
open static func indexHandlerGet(request: HTTPRequest, _ response: HTTPResponse) {
var dump = ""
do {
let x = request.session?.data
dump = try x.jsonEncodedString()
} catch {
dump = "\(error)"
}
var body = "Your Session ID is: \(request.session?.token ?? "")
Session data: \(dump)"
body += "CSRF Test Form"
body += "No CSRF Test Form"
response.setBody(string: header+body+footer)
response.completed()
}
/* =================================================================================================================
Index
================================================================================================================= */
open static func indexHandlerGetJSON(request: HTTPRequest, _ response: HTTPResponse) {
var opt = [String: Any]()
opt["sessionid"] = request.session?.token
opt["dump"] = request.session?.data
_ = try? response.setBody(json: opt)
response.completed()
}
/* =================================================================================================================
CORS
================================================================================================================= */
open static func CORSHandlerGet(request: HTTPRequest, _ response: HTTPResponse) {
response.addHeader(.contentType, value: "application/json")
let _ = try? response.setBody(json: ["Success":"CORS Request"])
response.completed()
}
/* =================================================================================================================
formNoCSRF
================================================================================================================= */
open static func formNoCSRF(request: HTTPRequest, _ response: HTTPResponse) {
var body = "Your Session ID is: \(request.session?.token ?? "")"
body += "No CSRF Form"
body += "NOTE: You should get a failed request because there is no CSRF"
body += ""
body += ""
body += ""
response.setBody(string: header+body+footer)
response.completed()
}
/* =================================================================================================================
formWithCSRF
================================================================================================================= */
open static func formWithCSRF(request: HTTPRequest, _ response: HTTPResponse) {
let t = request.session?.data["csrf"] as? String ?? ""
var body = "Your Session ID is: \(request.session?.token ?? "")"
body += "CSRF Form"
body += ""
body += ""
body += ""
body += ""
response.setBody(string: header+body+footer)
response.completed()
}
/* =================================================================================================================
formReceive
================================================================================================================= */
open static func formReceive(request: HTTPRequest, _ response: HTTPResponse) {
// print("in formReceive")
var body = "Your Session ID is: \(request.session?.token ?? "")"
body += "CSRF Test response"
body += "Params: \(request.postParams)"
response.setBody(string: header+body+footer)
response.completed()
}
static var header = "<html><head><link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\"><title>Perfect Sessions Demo</title><style>.header,body{padding-bottom:20px}.header,.jumbotron{border-bottom:1px solid #e5e5e5}body{padding-top:20px}.footer,.header,.marketing{padding-right:15px;padding-left:15px}.header h3{margin-top:0;margin-bottom:0;line-height:40px}.footer{padding-top:19px;color:#777;border-top:1px solid #e5e5e5}@media (min-width:768px){.container{max-width:730px}}.container-narrow>hr{margin:30px 0}.jumbotron{text-align:center}.jumbotron .btn{padding:14px 24px;font-size:21px}.marketing{margin:40px 0}.marketing p+h4{margin-top:28px}@media screen and (min-width:768px){.footer,.header,.marketing{padding-right:0;padding-left:0}.header{margin-bottom:30px}.jumbotron{border-bottom:0}}</style></head><body><div class=\"container\"><div class=\"header clearfix\"><h3 class=\"text-muted\"><a href=\"/\">Perfect Sessions Demo</a></h3></div>"
static var footer = "</div></body></html>"
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

xcode에서 실행 후 브라우저를 열고 localhost:8181을 호출하면 아래와 같이 서버에 접속한 Session 정보를 볼수 있습니다.


Redis에 접속해 Session ID가 추가되었는지 확인해 봅시다.

1
2
127.0.0.1:6379> keys *
1) "7683CBB2-5F2B-44E9-A594-F65F201B860D"
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

여기까지는 Perfect-Session-Redis-Demo의 내용이었습니다.

다음 Post에서 Redis의 Set, Get을 구현해 보겠습니다.