summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2020-08-05 19:18:16 +0300
committerAndrej Mihajlov <and@mullvad.net>2020-08-18 17:18:20 +0200
commit2e9143040fbd7f9e26b397ba6051e2f91b0f732d (patch)
treeb9d6e3cfdb4554ba20c473257648727fea4993b5
parent1ff1153eb12ac0607627d3d56ba4bfa69071c641 (diff)
downloadmullvadvpn-2e9143040fbd7f9e26b397ba6051e2f91b0f732d.tar.xz
mullvadvpn-2e9143040fbd7f9e26b397ba6051e2f91b0f732d.zip
Add text file streamer
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/Logging/TextFileStream.swift117
2 files changed, 121 insertions, 0 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index de3226aa5d..6ce6bcc2c7 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -39,6 +39,7 @@
580EE22824B3289300F9D8A1 /* AssociatedValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580EE22724B3289300F9D8A1 /* AssociatedValue.swift */; };
580EE22924B3289300F9D8A1 /* AssociatedValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580EE22724B3289300F9D8A1 /* AssociatedValue.swift */; };
5811DE50239014550011EB53 /* NEVPNStatus+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */; };
+ 58141EC924DAC0ED0013F79C /* TextFileStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58141EC824DAC0ED0013F79C /* TextFileStream.swift */; };
5815039724D6ECAE00C9C50E /* CustomFormatLogHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039624D6ECAE00C9C50E /* CustomFormatLogHandler.swift */; };
5815039824D6ECAE00C9C50E /* CustomFormatLogHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039624D6ECAE00C9C50E /* CustomFormatLogHandler.swift */; };
5815039D24D6ECE600C9C50E /* TextFileOutputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */; };
@@ -268,6 +269,7 @@
580EE22324B3243100F9D8A1 /* AsyncBlockOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncBlockOperation.swift; sourceTree = "<group>"; };
580EE22724B3289300F9D8A1 /* AssociatedValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssociatedValue.swift; sourceTree = "<group>"; };
5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+Debug.swift"; sourceTree = "<group>"; };
+ 58141EC824DAC0ED0013F79C /* TextFileStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFileStream.swift; sourceTree = "<group>"; };
5815039324D6EB7200C9C50E /* LogRotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRotation.swift; sourceTree = "<group>"; };
5815039624D6ECAE00C9C50E /* CustomFormatLogHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomFormatLogHandler.swift; sourceTree = "<group>"; };
5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFileOutputStream.swift; sourceTree = "<group>"; };
@@ -465,6 +467,7 @@
5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */,
581503A524D6F4AE00C9C50E /* Logging.swift */,
5815039324D6EB7200C9C50E /* LogRotation.swift */,
+ 58141EC824DAC0ED0013F79C /* TextFileStream.swift */,
);
path = Logging;
sourceTree = "<group>";
@@ -1032,6 +1035,7 @@
58561C99239A5D1500BD6B5E /* IPEndpoint.swift in Sources */,
58FD5BF22424F7D700112C88 /* UserInterfaceInteractionRestriction.swift in Sources */,
5811DE50239014550011EB53 /* NEVPNStatus+Debug.swift in Sources */,
+ 58141EC924DAC0ED0013F79C /* TextFileStream.swift in Sources */,
58C3A4B222456F1B00340BDB /* AccountInputGroupView.swift in Sources */,
58F840B22464491D0044E708 /* ChainedError.swift in Sources */,
58FAEDFF24533A7000CB0F5B /* KeychainReturn.swift in Sources */,
diff --git a/ios/MullvadVPN/Logging/TextFileStream.swift b/ios/MullvadVPN/Logging/TextFileStream.swift
new file mode 100644
index 0000000000..2ae9b3e82f
--- /dev/null
+++ b/ios/MullvadVPN/Logging/TextFileStream.swift
@@ -0,0 +1,117 @@
+//
+// TextFileStream.swift
+// MullvadVPN
+//
+// Created by pronebird on 05/08/2020.
+// Copyright © 2020 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import Darwin
+
+class TextFileStream<Codec> where Codec: UnicodeCodec {
+ private let readSource: DispatchSourceRead
+ private let fileDescriptor: Int32
+ private let queue = DispatchQueue(label: "net.mullvad.MullvadVPN.TextFileStream<\(Codec.self)>")
+ private let stringStream: StringStreamIterator<Codec>
+
+ init?(fileURL: URL, separator: Character, encoding: String.Encoding = .utf8) {
+ let filePath = fileURL.path.utf8CString.map { $0 }
+
+ let fileDescriptor = open(filePath, O_RDONLY)
+ if (fileDescriptor == -1) {
+ return nil
+ }
+
+ // Avoid blocking the read operation
+ _ = fcntl(fileDescriptor, F_SETFL, O_NONBLOCK);
+
+ let readSource = DispatchSource.makeReadSource(fileDescriptor: fileDescriptor, queue: queue)
+ readSource.setCancelHandler {
+ close(fileDescriptor)
+ }
+
+ stringStream = StringStreamIterator(separator: separator)
+
+ self.readSource = readSource
+ self.fileDescriptor = fileDescriptor
+ }
+
+ deinit {
+ readSource.cancel()
+ }
+
+ func read(_ handler: @escaping (String) -> Void) {
+ readSource.setEventHandler { [weak self] in
+ guard let self = self else { return }
+
+ let estimated = Int(self.readSource.data + 1)
+ var buffer = [Codec.CodeUnit](repeating: 0, count: estimated)
+ let actual = Darwin.read(self.fileDescriptor, &buffer, estimated)
+
+ if actual == -1 {
+ print("TextFileInputStream: read error: \(errno)")
+ }
+
+ if actual > 0 {
+ let bytes = buffer[..<actual]
+ self.stringStream.append(bytes: bytes)
+
+ while let s = self.stringStream.next() {
+ handler(s)
+ }
+ }
+ }
+ readSource.activate()
+ }
+
+ func cancel() {
+ readSource.cancel()
+ }
+
+}
+
+class StringStreamIterator<Codec>: IteratorProtocol where Codec: UnicodeCodec {
+ let separator: Character
+
+ private var string = ""
+ private var data = [Codec.CodeUnit]()
+ private var parser = Codec.ForwardParser()
+
+ init(separator: Character) {
+ self.separator = separator
+ }
+
+ func append<S>(bytes: S) where S: Sequence, S.Element == Codec.CodeUnit {
+ data.append(contentsOf: bytes)
+ }
+
+ func next() -> String? {
+ var dataIterator = data.makeIterator()
+ var bytesRead = 0
+
+ defer {
+ if bytesRead > 0 {
+ data.removeSubrange(..<bytesRead)
+ }
+ }
+
+ while case .valid(let encodedScalar) = parser.parseScalar(from: &dataIterator) {
+ let unicodeScalar = Codec.decode(encodedScalar)
+ let character = Character(unicodeScalar)
+
+ bytesRead += encodedScalar.count
+
+ if character == separator {
+ let returnString = string
+ string = ""
+
+ return returnString
+ } else {
+ string.append(character)
+ }
+ }
+
+ return nil
+ }
+}