fchat-rising/mobile/ios/F-Chat/File.swift

100 lines
4.6 KiB
Swift

import Foundation
import WebKit
class File: NSObject, WKScriptMessageHandler {
let encoder = JSONEncoder()
let fm = FileManager.default;
let baseDir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
override init() {
super.init();
try! fm.createDirectory(at: baseDir, withIntermediateDirectories: true, attributes: nil)
}
func escape(_ str: String) -> String {
return "'" + str.replacingOccurrences(of: "\'", with: "\\\'").replacingOccurrences(of: "\n", with: "\\n") + "'"
}
func userContentController(_ controller: WKUserContentController, didReceive message: WKScriptMessage) {
let data = message.body as! [String: AnyObject]
let key = data["_id"] as! String
do {
var result: String?
switch(data["_type"] as! String) {
case "readFile":
result = try readFile(data["name"] as! String, (data["start"] as! NSNumber?)?.uint64Value, data["length"] as! Int?)
case "writeFile":
try writeFile(data["name"] as! String, data["data"] as! String)
case "append":
try append(data["name"] as! String, data["data"] as! String)
case "listDirectories":
result = try listDirectories(data["name"] as! String)
case "listFiles":
result = try listFiles(data["name"] as! String)
case "getSize":
result = try getSize(data["name"] as! String)
case "ensureDirectory":
try ensureDirectory(data["name"] as! String)
default:
message.webView!.evaluateJavaScript("nativeError('\(key)',new Error('Unknown message type'))")
return
}
let output = result == nil ? "undefined" : result!;
message.webView!.evaluateJavaScript("nativeMessage('\(key)',\(output))")
} catch(let error) {
message.webView!.evaluateJavaScript("nativeError('\(key)',new Error('File-\(data["_type"]!): \(error.localizedDescription)'))")
}
}
func readFile(_ name: String, _ start: UInt64?, _ length: Int?) throws -> String? {
let url = baseDir.appendingPathComponent(name, isDirectory: false);
if(!fm.fileExists(atPath: url.path)) { return nil }
let fd = try FileHandle(forReadingFrom: url)
fd.seek(toFileOffset: start ?? 0)
let data: Data = length != nil ? fd.readData(ofLength: length!) : fd.readDataToEndOfFile();
fd.closeFile()
return escape(String(data: data, encoding: .utf8)!)
}
func writeFile(_ name: String, _ data: String) throws {
try data.write(to: baseDir.appendingPathComponent(name, isDirectory: false), atomically: true, encoding: .utf8)
}
func append(_ name: String, _ data: String) throws {
let url = baseDir.appendingPathComponent(name, isDirectory: false);
if(!fm.fileExists(atPath: url.path)) {
fm.createFile(atPath: url.path, contents: nil)
}
let fd = try FileHandle(forWritingTo: url)
fd.seekToEndOfFile()
fd.write(data.data(using: .utf8)!)
fd.closeFile()
}
func listDirectories(_ name: String) throws -> String {
let dirs = try fm.contentsOfDirectory(at: baseDir.appendingPathComponent(name, isDirectory: true), includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles]).filter {
try $0.resourceValues(forKeys: [.isDirectoryKey]).isDirectory == true
}.map { $0.lastPathComponent }
return escape(String(data: try JSONSerialization.data(withJSONObject: dirs), encoding: .utf8)!);
}
func listFiles(_ name: String) throws -> String {
let files = try fm.contentsOfDirectory(at: baseDir.appendingPathComponent(name, isDirectory: true), includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles]).filter {
try $0.resourceValues(forKeys: [.isDirectoryKey]).isDirectory == false
}.map { $0.lastPathComponent }
return escape(String(data: try JSONSerialization.data(withJSONObject: files), encoding: .utf8)!);
}
func getSize(_ name: String) throws -> String {
let path = baseDir.appendingPathComponent(name, isDirectory: false).path;
if(!fm.fileExists(atPath: path)) { return "0"; }
return String(try fm.attributesOfItem(atPath: path)[.size] as! UInt64)
}
func ensureDirectory(_ name: String) throws {
try fm.createDirectory(at: baseDir.appendingPathComponent(name, isDirectory: true), withIntermediateDirectories: true, attributes: nil)
}
}