on 157faf0 help sign in
5 files changed+3−251
since splitsnapshots
unifiedsplit
Sources/App/Models/Post.swift−147 Sources/App/boot.swift+1−62 Sources/App/configure.swift−32 Sources/App/routes.swift+1−9 cloud.yml+1−1
Sources/App/Models/Post.swiftdeleted−147
@@ -1,147 +0,0 @@
1−//
2−// Post.swift
3−// App
4−//
5−// Created by Ilya on 22/11/2018.
6−//
7−
8−import Foundation
9−import Vapor
10−
11−class Model {
12− var posts: [Int: Post] = [:]
13−
14− enum Error: AbortError {
15− var status: HTTPResponseStatus {return .notFound}
16−
17− var reason: String {return "User not found."}
18−
19− var identifier: String {return "userNotFound"}
20−
21− case notFound
22− }
23−
24− func getPost(for id: Post.Id, on worker: Worker) -> Future<Post> {
25− let out = worker.eventLoop.newPromise(Post.self)
26−
27− queue.async {
28− if let post = self.posts[id] {
29− out.succeed(result: post)
30− } else {
31− out.fail(error: Error.notFound)
32− }
33− }
34−
35− return out.futureResult
36− }
37−
38− func deleteRandom(on worker: Worker) -> Future<Post.Id> {
39− let out = worker.eventLoop.newPromise(Post.Id.self)
40−
41− if let post = self.posts.randomElement() {
42− self.queue.sync(flags: .barrier) {
43− self.posts[post.key] = nil
44− out.succeed(result: post.key)
45− }
46− } else {
47− out.fail(error: Error.notFound)
48− }
49−
50− return out.futureResult
51−
52− }
53−
54− func insert(post: Post) {
55− queue.sync(flags: .barrier) {
56− posts[post.id] = post
57− }
58− }
59−
60− private let queue = DispatchQueue(label: "soy.iko.Model")
61−}
62−
63−let postModel = Model()
64−
65−enum Event: Encodable {
66− func encode(to encoder: Encoder) throws {
67− var container = encoder.container(keyedBy: CodingKeys.self)
68− switch self {
69− case .delete(let id):
70− try container.encode(id, forKey: .id)
71− try container.encode("delete", forKey: .type)
72− case .add(let id):
73− try container.encode(id, forKey: .id)
74− try container.encode("add", forKey: .type)
75− }
76− }
77−
78− private enum CodingKeys: String, CodingKey {
79− case type
80− case id
81− }
82−
83− case delete(Post.Id)
84− case add(Post.Id)
85−}
86−
87−struct CyclicBuffer<T> {
88− var buffer: [T?]
89−
90− var index = 0
91− let size: Int
92− init(of size: Int) {
93− self.size = size
94− buffer = Array(repeating: nil, count: size)
95− }
96−
97− mutating func append(element: T?) {
98− queue.sync(flags: .barrier) {
99− buffer[index] = element
100− index = (index+1)%size
101− }
102− }
103−
104− func get(last number: Int, loop: Worker) -> Future<ArraySlice<T?>> {
105−
106− let out = loop.eventLoop.newPromise(ArraySlice<T?>.self)
107−
108−// var out: ArraySlice<T?>!
109− queue.async {
110− out.succeed(result: (self.buffer[self.index+1..<self.size] + self.buffer[0...max(number-1, self.index)]))
111− }
112−
113− return out.futureResult
114− }
115−
116− private let queue = DispatchQueue(label: "soy.iko.Buffer")
117−}
118−
119−var eventBuffer = CyclicBuffer<Event>(of: 100)
120−
121−struct Events: Encodable {
122− let error: String?
123− let events: [Event]?
124−}
125−
126−struct Post: Content {
127− typealias Id = Int
128−
129− let user: User
130− let text: String
131−
132− let id: Id = {
133− lastID += 1;
134− return lastID
135− }()
136−
137− static private var lastID: Int = 0
138−}
139−
140−struct User: Content {
141− let name: Name
142−}
143−
144−struct Name: Content {
145− let first: String
146− let second: String
147−}
Sources/App/boot.swift+1−62
@@ -1,67 +1,6 @@
11import Vapor
22
3−import Dispatch
4−
5−struct OpenSockets {
6− private(set) static var sockets: [Int: WebSocket] = [:]
7−
8− static func insert(_ socket: WebSocket) -> Int {
9− let out = id
10− id += 1
11− queue.sync {
12− sockets[out] = socket
13− }
14− return out
15− }
16−
17− static func remove(at id: Int) {
18− queue.async {
19− sockets[id] = nil
20− }
21− }
22−
23−// static func get(for id: Int) {
24−// var out: WebSocket!
25−// queue.sync {
26−// out = sockets[id]
27−// }
28−// }
29−
30− static let queue = DispatchQueue.init(label: "WS")
31−
32− private static var id = 0
33−}
34−
35−let enc = JSONEncoder()
36−
373/// Called after your application has initialized.
384public func boot(_ app: Application) throws {
39−
40− app.eventLoop.scheduleRepeatedTask(initialDelay: .seconds(10), delay: .seconds(10)) { (task: RepeatedTask) in
41− let _ = try app.client().get("https://baconipsum.com/api/?type=all-meat&paras=1&start-with-lorem=0")
42− .flatMap { try $0.content.decode([String].self) }
43− .do { (texts) in
44− guard let text = texts.first else { return }
45−
46− let p = Post.init(user: User(name: Name(first: "Акакий", second: "Программистович")), text: text)
47−
48− postModel.insert(post: p)
49−
50− eventBuffer.append(element: .add(p.id))
51−
52−
53− OpenSockets.sockets.values.forEach { ws in
54− ws.send(try! enc.encode(Events(error: nil, events: [.add(p.id)])))
55− }
56− }
57− }
58−
59− app.eventLoop.scheduleRepeatedTask(initialDelay: .seconds(205), delay: .seconds(10)) { (task: RepeatedTask) in
60− postModel.deleteRandom(on: app)
61− .whenSuccess({ (id) in
62− eventBuffer.append(element: .delete(id))
63−
64− OpenSockets.sockets.values.forEach {$0.send(try! enc.encode(Events(error: nil, events: [.delete(id)])))}
65− })
66− }
5+ // your code here
676}
Sources/App/configure.swift−32
@@ -29,37 +29,5 @@ public func configure(_ config: inout Config, _ env: inout Environment, _ servic
2929 var migrations = MigrationConfig()
3030 migrations.add(model: Todo.self, database: .sqlite)
3131 services.register(migrations)
32−
33− let ws = NIOWebSocketServer.default()
34−
35−
36− ws.get("postUpdates", Int.parameter) { (ws, req) in
37− if let lastTry = try? req.parameters.next(Int.self) {
38− eventBuffer.get(last: max(0, eventBuffer.index - lastTry), loop: req)
39− .map {$0.compactMap {$0}}
40− .map {Events.init(error: nil, events: $0)}
41− .map {try JSONEncoder().encode($0)}
42− .do { ws.send($0) }
43− }
44−
45− let socketID = OpenSockets.insert(ws)
46−
47−
48−// ws.onText({ (ws, text) in
49−// ws.send("\(id): \(text)")
50−// })
51− _ = ws.onClose.always {
52− print("closing")
53− OpenSockets.remove(at: socketID)
54− }
55− }
56−
57− ws.get("test") { (ws, req) in
58− ws.onText({ (ws, text) in
59− ws.send("pong")
60− })
61− }
62−
63− services.register(ws, as: WebSocketServer.self)
6432
6533}
Sources/App/routes.swift+1−9
@@ -11,15 +11,7 @@ public func routes(_ router: Router) throws {
1111 router.get("hello") { req in
1212 return "Hello, world!"
1313 }
14−
15− router.get("post", Int.parameter) { req -> Future<Post> in
16− return postModel.getPost(for: try req.parameters.next(Int.self), on: req)
17− }
18−
19− router.get("openSockets") { (req) in
20− return OpenSockets.sockets.count
21− }
22−
14+
2315 // Example of configuring a controller
2416 let todoController = TodoController()
2517 router.get("todos", use: todoController.index)
cloud.yml+1−1
@@ -1,3 +1,3 @@
11type: "vapor"
2−swift_version: "4.2.0"
2+swift_version: "4.1.0"
33run_parameters: "serve --port 8080 --hostname 0.0.0.0"