Skip to content

Commit

Permalink
Improve confiuguration loading
Browse files Browse the repository at this point in the history
  • Loading branch information
ZekeSnider committed Aug 22, 2020
1 parent 657e0fb commit a4b1823
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 97 deletions.
46 changes: 35 additions & 11 deletions Jared.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
7F84B62E1CC511B80059A82B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B3BBA7CD1CB3259A00E1749C /* Localizable.strings */; };
7FE220ED1CB3C8340081CE23 /* podfile in Resources */ = {isa = PBXBuildFile; fileRef = 7FE220EC1CB3C8340081CE23 /* podfile */; };
7FF077EB1CBCFFCB008E33CB /* SendImage.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 7FF077EA1CBCFFCB008E33CB /* SendImage.scpt */; };
B30578D324F1927D00C43037 /* ConfigurationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30578D224F1927D00C43037 /* ConfigurationHelper.swift */; };
B30578D424F1927D00C43037 /* ConfigurationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30578D224F1927D00C43037 /* ConfigurationHelper.swift */; };
B30F765624C5742800ADF57B /* SendTextUI.scpt in Resources */ = {isa = PBXBuildFile; fileRef = B30F765424C5740800ADF57B /* SendTextUI.scpt */; };
B319235724DD311B001904BA /* InternalModuleTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B319235624DD311B001904BA /* InternalModuleTest.swift */; };
B319235824DD319D001904BA /* InternalModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BF17C3244EBF4900CC44C5 /* InternalModule.swift */; };
Expand Down Expand Up @@ -54,6 +56,7 @@
B375A65921EB14470073F09F /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B375A65821EB14470073F09F /* AboutViewController.swift */; };
B37E82821FA85B210069E15D /* SendTextSingleBuddy.scpt in Resources */ = {isa = PBXBuildFile; fileRef = B37E82811FA85B210069E15D /* SendTextSingleBuddy.scpt */; };
B38BB6AD24EB99BE000700F7 /* Webhook.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3B7E52824EA579600A3FBD1 /* Webhook.swift */; };
B38BB6AF24EBB4D8000700F7 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B36C8D7E24EA655900C00A99 /* Configuration.swift */; };
B39A65E01CC1FB1B003E26B0 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B39A65DF1CC1FB1B003E26B0 /* PluginManager.swift */; };
B39F2B391CB3BCA700C0D35C /* SendText.scpt in Resources */ = {isa = PBXBuildFile; fileRef = B39F2B381CB3BCA700C0D35C /* SendText.scpt */; };
B3A4C61423B867E300B7F009 /* MessageRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3A4C61323B867E300B7F009 /* MessageRequest.swift */; };
Expand Down Expand Up @@ -156,6 +159,7 @@
7FE220EC1CB3C8340081CE23 /* podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
7FF077EA1CBCFFCB008E33CB /* SendImage.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; path = SendImage.scpt; sourceTree = "<group>"; };
8490C38E773007C8CC882DCB /* Pods-Jared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Jared.release.xcconfig"; path = "Pods/Target Support Files/Pods-Jared/Pods-Jared.release.xcconfig"; sourceTree = "<group>"; };
B30578D224F1927D00C43037 /* ConfigurationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationHelper.swift; sourceTree = "<group>"; };
B30F765424C5740800ADF57B /* SendTextUI.scpt */ = {isa = PBXFileReference; lastKnownFileType = text; path = SendTextUI.scpt; sourceTree = "<group>"; };
B30F765724C574FD00ADF57B /* JaredRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = JaredRelease.entitlements; sourceTree = "<group>"; };
B319235624DD311B001904BA /* InternalModuleTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalModuleTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -358,6 +362,30 @@
path = JaredTests;
sourceTree = "<group>";
};
B38BB6AE24EBB4CE000700F7 /* Structures */ = {
isa = PBXGroup;
children = (
B36C8D7E24EA655900C00A99 /* Configuration.swift */,
B3B7E52324E9EE2000A3FBD1 /* AutomationPermissionState.swift */,
B3B7E52824EA579600A3FBD1 /* Webhook.swift */,
B3A4C61323B867E300B7F009 /* MessageRequest.swift */,
);
name = Structures;
sourceTree = "<group>";
};
B38BB6B024EBB530000700F7 /* Helpers */ = {
isa = PBXGroup;
children = (
B353946124E64DDE00F9424A /* PersistentContainer.swift */,
B30578D224F1927D00C43037 /* ConfigurationHelper.swift */,
B3FB28F124E9BAF7003BA6CB /* PermissionsHelper.swift */,
B3327DC32206607B009DD882 /* ContactHelper.swift */,
7F0E931C1D02FC250096BABE /* Global.swift */,
B3FB28F324E9BCBD003BA6CB /* JaredConstants.swift */,
);
name = Helpers;
sourceTree = "<group>";
};
B39EC1691CB01F55002C3161 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -395,24 +423,17 @@
B30F765424C5740800ADF57B /* SendTextUI.scpt */,
B37E82811FA85B210069E15D /* SendTextSingleBuddy.scpt */,
B361EEBA1F1DE24C0041113C /* config.json */,
B353946124E64DDE00F9424A /* PersistentContainer.swift */,
B3EF1DA92206E09B00953DE7 /* Jared.swift */,
B3BF17C1244EBE9A00CC44C5 /* Router.swift */,
B39A65DF1CC1FB1B003E26B0 /* PluginManager.swift */,
B3327DC522066427009DD882 /* WebHookManager.swift */,
B3327DC32206607B009DD882 /* ContactHelper.swift */,
B3FB28F124E9BAF7003BA6CB /* PermissionsHelper.swift */,
B3FB28F324E9BCBD003BA6CB /* JaredConstants.swift */,
B3C59283224DD17900116ECB /* JaredWebServer.swift */,
B3B7E52324E9EE2000A3FBD1 /* AutomationPermissionState.swift */,
B3A4C61323B867E300B7F009 /* MessageRequest.swift */,
B35CE7142196AD4E002F52A7 /* DatabaseHandler.swift */,
7F0E931C1D02FC250096BABE /* Global.swift */,
B3EF1DA92206E09B00953DE7 /* Jared.swift */,
B36C8D7E24EA655900C00A99 /* Configuration.swift */,
B3B7E52824EA579600A3FBD1 /* Webhook.swift */,
B3BBA7CD1CB3259A00E1749C /* Localizable.strings */,
B38BB6B024EBB530000700F7 /* Helpers */,
B38BB6AE24EBB4CE000700F7 /* Structures */,
B3BF17C9244ED26800CC44C5 /* Delegates */,
B39EC17C1CB01FDD002C3161 /* Modules */,
B3BBA7CD1CB3259A00E1749C /* Localizable.strings */,
7FE220EC1CB3C8340081CE23 /* podfile */,
);
path = Jared;
Expand Down Expand Up @@ -785,6 +806,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B30578D324F1927D00C43037 /* ConfigurationHelper.swift in Sources */,
B347A4A724DD0FCF00E93657 /* Jared.swift in Sources */,
B3BF17C8244ECC0E00CC44C5 /* PluginManagerDelegate.swift in Sources */,
B3A4C61423B867E300B7F009 /* MessageRequest.swift in Sources */,
Expand Down Expand Up @@ -824,6 +846,7 @@
B3B844D224DA6BBB00DC162A /* JaredWebServer.swift in Sources */,
B3B844CC24DA671E00DC162A /* DiskAccessDelegate.swift in Sources */,
B319235724DD311B001904BA /* InternalModuleTest.swift in Sources */,
B38BB6AF24EBB4D8000700F7 /* Configuration.swift in Sources */,
B3B844C924D92D1500DC162A /* ContactHelper.swift in Sources */,
B3B844C824D92C2200DC162A /* DatabaseHandler.swift in Sources */,
B3B844C024D8F91900DC162A /* DatabaseHandlerTest.swift in Sources */,
Expand All @@ -833,6 +856,7 @@
B3BF17CA244FDA3F00CC44C5 /* MessageDelegate.swift in Sources */,
B3B844C524D9288000DC162A /* RouterDelegate.swift in Sources */,
B3B844B824D7791800DC162A /* ActionTypeTest.swift in Sources */,
B30578D424F1927D00C43037 /* ConfigurationHelper.swift in Sources */,
B3B844C724D9298000DC162A /* MockRouter.swift in Sources */,
B347A4AD24DD170C00E93657 /* ActionTest.swift in Sources */,
B36710E224DFB5EC00DA1C5D /* JaredMock.swift in Sources */,
Expand Down
12 changes: 9 additions & 3 deletions Jared/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@

import Foundation

class ConfigurationFile: Decodable {
struct ConfigurationFile: Decodable {
let routes: [String: RouteConfiguration]
let webhooks: [Webhook]
let webServer: WebserverConfiguration

init() {
routes = [:]
webhooks = []
webServer = WebserverConfiguration(port: 3000)
}
}

class WebserverConfiguration: Decodable {
struct WebserverConfiguration: Decodable {
let port: Int
}

class RouteConfiguration: Decodable {
struct RouteConfiguration: Decodable {
let disabled: Bool
}
58 changes: 58 additions & 0 deletions Jared/ConfigurationHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// ConfigurationHelper.swift
// Jared
//
// Created by Zeke Snider on 8/22/20.
// Copyright © 2020 Zeke Snider. All rights reserved.
//

import Foundation

struct ConfigurationHelper {
static let fileManager = FileManager.default

static func getConfiguration() -> ConfigurationFile {
let configPath = ConfigurationHelper.getSupportDirectory()
.appendingPathComponent("config.json")
ConfigurationHelper.createConfigFileIfNotExists(at: configPath, using: fileManager)

//Read the JSON config file
var config: ConfigurationFile
let jsonData = try? NSData(contentsOfFile: configPath.path, options: .mappedIfSafe)
if let parsedConfig = try? JSONDecoder().decode(ConfigurationFile.self, from: jsonData! as Data) {
config = parsedConfig
} else {
NSLog("Unable to parse configuration file, using default")
config = ConfigurationFile()
}

return config
}

static func getSupportDirectory() -> URL {
let filemanager = FileManager.default
let appsupport = filemanager.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let supportDir = appsupport.appendingPathComponent("Jared")

try! filemanager.createDirectory(at: supportDir, withIntermediateDirectories: true, attributes: nil)

return supportDir
}

static func getPluginDirectory() -> URL {
let supportDir = getSupportDirectory()
.appendingPathComponent("Plugins")

try! fileManager.createDirectory(at: supportDir, withIntermediateDirectories: true, attributes: nil)

return supportDir
}

//Copy an empty config file if the conig file does not exist
private static func createConfigFileIfNotExists(at path: URL, using fileManager: FileManager) {
//Copy an empty config file if the conig file does not exist
if !fileManager.fileExists(atPath: path.path) {
try! fileManager.copyItem(at: (Bundle.main.resourceURL?.appendingPathComponent("config.json"))!, to: path)
}
}
}
39 changes: 4 additions & 35 deletions Jared/JaredWebServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ class JaredWebServer: NSObject {
var server: Server!
var port: Int!
var sender: MessageSender
var configurationURL: URL

init(sender: MessageSender, configurationURL: URL) {
self.configurationURL = configurationURL
init(sender: MessageSender, configuration: WebserverConfiguration) {
self.sender = sender
super.init()
defaults = UserDefaults.standard
server = Server()
server.route(.POST, "message", handleMessageRequest)

port = assignPort()
port = configuration.port

defaults.addObserver(self, forKeyPath: JaredConstants.restApiIsDisabled, options: .new, context: nil)
updateServerState()
Expand All @@ -29,35 +27,6 @@ class JaredWebServer: NSObject {
UserDefaults.standard.removeObserver(self, forKeyPath: JaredConstants.jaredIsDisabled)
}

// Attempt to pull the port number from the config
func assignPort() -> Int {
let filemanager = FileManager.default
do {
// If config file does not exist, use default port
guard filemanager.fileExists(atPath: configurationURL.path) else {
return JaredWebServer.DEFAULT_PORT
}

//Read the JSON config file
let jsonData = try! NSData(contentsOfFile: configurationURL.path, options: .mappedIfSafe)

// If the JSON format is not as expected at all, use the default port
guard let jsonResult = ((try? JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String:AnyObject]) as [String : AnyObject]??) else {
return JaredWebServer.DEFAULT_PORT
}

guard let serverConfig = jsonResult?["webserver"] as? [String : AnyObject] else {
return JaredWebServer.DEFAULT_PORT
}

guard let configPort = serverConfig["port"] as? NSNumber else {
return JaredWebServer.DEFAULT_PORT
}

return Int(truncating: configPort)
}
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (keyPath == JaredConstants.restApiIsDisabled) {
updateServerState()
Expand All @@ -73,11 +42,11 @@ class JaredWebServer: NSObject {

}

func start() {
public func start() {
try? server.start(port: port)
}

func stop() {
public func stop() {
server.stop()
}

Expand Down
45 changes: 9 additions & 36 deletions Jared/PluginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,56 +13,33 @@ class PluginManager: PluginManagerDelegate {
var FrameworkVersion: String = "J3.0.0"
private var modules: [RoutingModule] = []
private var bundles: [Bundle] = []
var supportDir: URL?
var pluginDir: URL
var disabled = false
var config: ConfigurationFile
var webhooks: [String]?
var webHookManager: WebHookManager
var sender: MessageSender
public var router: Router!

init (sender: MessageSender) {
init (sender: MessageSender, configuration: ConfigurationFile, pluginDir: URL) {
self.sender = sender
let filemanager = FileManager.default
let appsupport = filemanager.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let supportDir = appsupport.appendingPathComponent("Jared")
let pluginDir = supportDir.appendingPathComponent("Plugins")

try! filemanager.createDirectory(at: supportDir, withIntermediateDirectories: true, attributes: nil)
try! filemanager.createDirectory(at: pluginDir, withIntermediateDirectories: true, attributes: nil)
self.pluginDir = pluginDir
self.config = configuration

let configPath = supportDir.appendingPathComponent("config.json")
do {
PluginManager.createConfigFileIfNotExists(at: configPath, using: filemanager)

//Read the JSON config file
let jsonData = try! NSData(contentsOfFile: supportDir.appendingPathComponent("config.json").path, options: .mappedIfSafe)
self.config = try! JSONDecoder().decode(ConfigurationFile.self, from: jsonData as Data)
}

webHookManager = WebHookManager(webhooks: config.webhooks, sender: sender)
webHookManager = WebHookManager(webhooks: configuration.webhooks, sender: sender)
router = Router(pluginManager: self, messageDelegates: [webHookManager])

loadPlugins(pluginDir)
loadPlugins()
addInternalModules()
}

//Copy an empty config file if the conig file does not exist
private static func createConfigFileIfNotExists(at path: URL, using fileManager: FileManager) {
//Copy an empty config file if the conig file does not exist
if !fileManager.fileExists(atPath: path.path) {
try! fileManager.copyItem(at: (Bundle.main.resourceURL?.appendingPathComponent("config.json"))!, to: path)
}
}


private func addInternalModules() {
modules.append(CoreModule(sender: sender))
modules.append(InternalModule(sender: sender, pluginManager: self))
modules.append(webHookManager)
}

func loadPlugins(_ pluginDir: URL) {
func loadPlugins() {
//Loop through all files in our plugin directory
let filemanager = FileManager.default
let files = filemanager.enumerator(at: pluginDir, includingPropertiesForKeys: [],
Expand Down Expand Up @@ -108,11 +85,7 @@ class PluginManager: PluginManagerDelegate {
modules.append(module)
}

func reload() {
let appsupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let supportDir = appsupport.appendingPathComponent("Jared")
let pluginDir = supportDir.appendingPathComponent("Plugins")

func reload() {
modules.removeAll()

for bundle in bundles {
Expand All @@ -121,7 +94,7 @@ class PluginManager: PluginManagerDelegate {

bundles.removeAll()

loadPlugins(pluginDir)
loadPlugins()
addInternalModules()
}

Expand Down
2 changes: 2 additions & 0 deletions Jared/WebHookManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class WebHookManager: MessageDelegate, RoutingModule {
}

public func updateHooks(to hooks: [Webhook]?) {
// Change all routes to have a callback that calls the webhook manager's
// notify route method
self.webhooks = (hooks ?? []).map({ (hook) -> Webhook in
var newHook = hook
newHook.routes = (newHook.routes ?? []).map({ (route) -> Route in
Expand Down
5 changes: 2 additions & 3 deletions JaredTests/JaredWebServerTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ class JaredWebServerTest: XCTestCase {

override func setUp() {
jaredMock = JaredMock()
let bundle = Bundle(for: type(of: self))
testDatabaseLocation = bundle.url(forResource: "config", withExtension: "json")
webServer = JaredWebServer(sender: jaredMock, configurationURL: testDatabaseLocation)
let configuration = WebserverConfiguration(port: 3005)
webServer = JaredWebServer(sender: jaredMock, configuration: configuration)
}

override func tearDown() {
Expand Down
Loading

0 comments on commit a4b1823

Please sign in to comment.