Skip to content

Commit

Permalink
refactored code and added retry mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
raygesualdo committed Aug 13, 2019
1 parent 8e45e0a commit 24629a1
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 52 deletions.
23 changes: 23 additions & 0 deletions program/Sources/amiunlocked/config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Configuration

// Start a configuration manager, load configuration from an adjacent
// `config.json` file, cast config values to appropriate types, and
// fail if required config values are not present
struct Config {
var url: String
var writeKey: String
init() {
let manager = ConfigurationManager()
manager.load(file: "config.json")
url = manager["url"] as? String ?? ""
writeKey = manager["writeKey"] as? String ?? ""

if url == "" {
fatalError("The config parameter 'url' is required. Set it in 'config.json' and please try again.")
}

if writeKey == "" {
fatalError("The config parameter 'writeKey' is required. Set it in 'config.json' and please try again.")
}
}
}
57 changes: 5 additions & 52 deletions program/Sources/amiunlocked/main.swift
Original file line number Diff line number Diff line change
@@ -1,74 +1,27 @@
import Cocoa
import Configuration
import Foundation
import Just

// Enumerate valid states for our computer: "locked" and "unlocked"
enum State: String {
case locked
case unlocked
}

// Section: Configuration
// Start a configuration manager, load configuration from an adjacent
// `config.json` file, cast config values to appropriate types, and
// fail if required config values are not present
let manager = ConfigurationManager()
manager.load(file: "config.json")
let url = manager["url"] as? String ?? ""
let writeKey = manager["writeKey"] as? String ?? ""
var sync = Sync()

if url == "" {
fatalError("The config parameter 'url' is required. Set it in 'config.json' and please try again.")
}

if writeKey == "" {
fatalError("The config parameter 'writeKey' is required. Set it in 'config.json' and please try again.")
}

// Section: Network Requests
// Functions to create UTC timestamps and make network requests
// to the kvdb bucket with a given `State`
func getISOTimestamp() -> String {
if #available(macOS 10.12, *) {
let date = Date()
let dateFormatter = ISO8601DateFormatter()
return dateFormatter.string(from: date)
} else {
fatalError("This process only runs on macOS 10.12+.")
}
}

func sendRequest(state: State) {
let r = Just.post(
url,
json: ["state": state.rawValue, "updatedAt": getISOTimestamp()],
auth: (writeKey, "")
)
if r.ok {
NSLog("Network: request succeeded")
} else {
NSLog("Network: request failed")
}
}

// Section: Event Listeners
// The event listeners listening for `screenIsLocked` and `screenIsUnlocked`
// events, and the callback function to log and make a network request in
// response to a triggered event
func logAndSendRequest(notification: Notification, state: State) {
func logAndSync(notification: Notification, state: State) {
NSLog("Event: \(notification.name.rawValue)")
sendRequest(state: state)
sync.initializeSync(state: state)
}

let dnc = DistributedNotificationCenter.default()

dnc.addObserver(forName: .init("com.apple.screenIsLocked"), object: nil, queue: .main) { notification in
logAndSendRequest(notification: notification, state: State.locked)
logAndSync(notification: notification, state: State.locked)
}

dnc.addObserver(forName: .init("com.apple.screenIsUnlocked"), object: nil, queue: .main) { notification in
logAndSendRequest(notification: notification, state: State.unlocked)
logAndSync(notification: notification, state: State.unlocked)
}

// Let's do this thing!
Expand Down
61 changes: 61 additions & 0 deletions program/Sources/amiunlocked/sync.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Cocoa
import Just

private func getISOTimestamp() -> String {
if #available(macOS 10.12, *) {
let date = Date()
let dateFormatter = ISO8601DateFormatter()
return dateFormatter.string(from: date)
} else {
fatalError("This process only runs on macOS 10.12+.")
}
}

class Sync {
private static let config = Config()

enum SyncStatus {
case pending(nextState: State)
case success
case failure(retryState: State)
}

var syncStatus: SyncStatus = .success
private var task: DispatchWorkItem?

func initializeSync(state: State) {
syncStatus = .pending(nextState: state)
handleSync()
}

private func handleSync() {
if task != nil { task!.cancel() }

switch syncStatus {
case let .pending(nextState):
sendRequest(state: nextState)
case .success:
break
case let .failure(retryState):
syncStatus = .pending(nextState: retryState)
sendRequest(state: retryState)
}
}

private func sendRequest(state: State) {
let r = Just.post(
Sync.config.url,
json: ["state": state.rawValue, "updatedAt": getISOTimestamp()],
auth: (Sync.config.writeKey, "")
)
if r.ok {
NSLog("Network: request succeeded")
syncStatus = .success
} else {
NSLog("Network: request failed")
syncStatus = .failure(retryState: state)
task = DispatchWorkItem { self.handleSync() }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task!)
}
}
}

0 comments on commit 24629a1

Please sign in to comment.