Created
February 27, 2019 12:41
-
-
Save BenziAhamed/6bff0984182244e42e01e563d5cf6961 to your computer and use it in GitHub Desktop.
Simulates a chat room
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
import PlaygroundSupport | |
PlaygroundPage.current.needsIndefiniteExecution = true | |
struct ChatMessage { | |
let id: String | |
let senderId: String | |
let message: String | |
let timestamp: Double | |
} | |
extension ChatMessage : CustomDebugStringConvertible { | |
var debugDescription: String { | |
let t = String(format: "%06.3f", timestamp) | |
return "[\(t)] \(senderId): \(message)" | |
} | |
} | |
protocol ChatRoomProxy : class { | |
var elapsedTime: TimeInterval { get } | |
var users: [String] { get } | |
func push(message: ChatMessage) | |
} | |
extension ChatRoomProxy { | |
func pushText(_ text: String) { | |
let m = ChatMessage.init(id: UUID().uuidString, senderId: users.first!, message: text, timestamp: elapsedTime) | |
push(message: m) | |
} | |
func pushHello(timeOffset: TimeInterval = 0) { | |
let m = ChatMessage.init(id: UUID().uuidString, senderId: users.randomElement()!, message: MessageGenerator.hello, timestamp: elapsedTime + timeOffset) | |
push(message: m) | |
} | |
} | |
class ChatRoomUpdateSource { | |
func update(proxy: ChatRoomProxy) { } | |
} | |
class ChatRoom : ChatRoomProxy { | |
let users: [String] | |
let tickInterval: TimeInterval | |
private let updateSources: [ChatRoomUpdateSource] | |
private var messages: [ChatMessage] = [] | |
private let q = DispatchQueue(label: "com.gojek.chatroom") | |
private(set) var elapsedTime: TimeInterval = 0 | |
var onMessageReceived: ((ChatMessage) -> Void)? | |
private var timer: Timer? | |
init(users: [String], updateSources: [ChatRoomUpdateSource], tickInterval: TimeInterval = 0.5) { | |
self.users = users | |
self.updateSources = updateSources | |
self.tickInterval = tickInterval | |
} | |
func start() { | |
timer = Timer.scheduledTimer(withTimeInterval: tickInterval, repeats: true, block: { timer in | |
self.updateSources.forEach { $0.update(proxy: self) } | |
self.elapsedTime += self.tickInterval | |
}) | |
} | |
func stop() { | |
timer?.invalidate() | |
elapsedTime = 0 | |
} | |
func push(message: ChatMessage) { | |
q.sync { | |
self.messages.append(message) | |
self.onMessageReceived?(message) | |
} | |
} | |
} | |
struct MessageGenerator { | |
static var hello: String { | |
return ["Hi", "Hello", "Hey there", "Hiya", "Aloha", | |
"How r u?", "Hows it been?", "Yo", "Dude!", "Hey bro", | |
"Hi hi", "Heya", "Hi yall", "Hey fellas", "Hoho", | |
"Long time!", "Ahem", "Heya", "Hellaws", "his", | |
"hiya", "hello", "hey", "heya", "hey there" | |
].randomElement()! | |
} | |
} | |
struct ScheduledTask { | |
let trigger: TimeInterval | |
let minRange: TimeInterval | |
let maxRange: TimeInterval | |
let action: (ChatRoomProxy) -> Void | |
let repeats: Bool | |
} | |
extension ScheduledTask { | |
static func once(at: TimeInterval, action: @escaping (ChatRoomProxy) -> Void) -> ScheduledTask { | |
return ScheduledTask(trigger: at, minRange: 0, maxRange: 0, action: action, repeats: false) | |
} | |
static func every(interval: TimeInterval, action: @escaping (ChatRoomProxy) -> Void, minRange: TimeInterval = 0, maxRange: TimeInterval = 0) -> ScheduledTask { | |
return ScheduledTask(trigger: interval, minRange: minRange, maxRange: maxRange, action: action, repeats: true) | |
} | |
var initialTrigger: TimeInterval { | |
if !repeats { | |
return trigger | |
} | |
return nextTrigger | |
} | |
var nextTrigger: TimeInterval { | |
if !repeats { | |
return TimeInterval.greatestFiniteMagnitude | |
} | |
if minRange != 0, maxRange != 0 { | |
return trigger | |
} | |
let min: TimeInterval = trigger - minRange | |
let max: TimeInterval = trigger + maxRange | |
let random: TimeInterval = TimeInterval.random(in: min...max) | |
return random | |
} | |
} | |
class ScheduledChatRoomUpdateSource : ChatRoomUpdateSource { | |
class ScheduledTrigger { | |
var nextTrigger: TimeInterval | |
let task: ScheduledTask | |
init(_ task: ScheduledTask) { | |
self.task = task | |
self.nextTrigger = task.initialTrigger | |
} | |
func process(proxy: ChatRoomProxy) { | |
if proxy.elapsedTime >= nextTrigger { | |
task.action(proxy) | |
nextTrigger = proxy.elapsedTime + task.nextTrigger | |
} | |
} | |
} | |
private var triggers = [ScheduledTrigger]() | |
func once(at: TimeInterval, action: @escaping (ChatRoomProxy) -> Void) { | |
triggers.append(ScheduledTrigger.init(ScheduledTask.once(at: at, action: action))) | |
} | |
func every(interval: TimeInterval, minRange: TimeInterval = 0, maxRange: TimeInterval = 0, action: @escaping (ChatRoomProxy) -> Void) { | |
triggers.append(ScheduledTrigger.init(ScheduledTask.every(interval: interval, action: action, minRange: minRange, maxRange: maxRange))) | |
} | |
override func update(proxy: ChatRoomProxy) { | |
triggers.forEach { | |
$0.process(proxy: proxy) | |
} | |
} | |
} | |
extension ChatRoom { | |
static func create() -> ChatRoom { | |
let schedule = ScheduledChatRoomUpdateSource() | |
schedule.once(at: 0) { (proxy) in | |
proxy.pushText("🏁 START") | |
} | |
schedule.every(interval: 5.0) { (proxy) in | |
proxy.pushText("🏁 CHECKPOINT") | |
} | |
schedule.every(interval: 2.0) { (proxy) in | |
let offset = [-1.0,1.0].randomElement()! * TimeInterval.random(in: 0.0...4.0) | |
proxy.pushHello(timeOffset: offset) | |
} | |
let room = ChatRoom(users: ["A", "B", "C", "D", "E", "F", "G"], updateSources: [schedule]) | |
return room | |
} | |
} | |
let room = ChatRoom.create() | |
room.onMessageReceived = { message in | |
print(message) | |
} | |
room.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Prints a random message stream, with induced latencies when receiving messages.
See sample output below