Created
September 24, 2018 08:56
-
-
Save seivan/e559c4b03b6c6e329912b3fc86f2bdf0 to your computer and use it in GitHub Desktop.
Long running Swift process (for running under BeamVM through ports)
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
//// | |
//// CustomFileHandler.swift | |
//// StatefulProcess | |
//// | |
//// Created by Seivan Heidari on 18/07/03. | |
//// | |
// | |
import Foundation | |
#if os(Linux) | |
import Glibc | |
#else | |
import Darwin | |
#endif | |
func fdZero(_ set: inout fd_set) { | |
#if os(Linux) | |
set.__fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
#else | |
set.fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
#endif | |
} | |
func fdIsSet(_ descriptor: Int32, _ set: inout fd_set) -> Bool { | |
#if os(Linux) | |
let intOffset = Int(descriptor / 32) | |
let bitOffset = Int(descriptor % 32) | |
let mask = Int(1 << bitOffset) | |
switch intOffset { | |
case 0: return set.__fds_bits.0 & mask != 0 | |
case 1: return set.__fds_bits.1 & mask != 0 | |
case 2: return set.__fds_bits.2 & mask != 0 | |
case 3: return set.__fds_bits.3 & mask != 0 | |
case 4: return set.__fds_bits.4 & mask != 0 | |
case 5: return set.__fds_bits.5 & mask != 0 | |
case 6: return set.__fds_bits.6 & mask != 0 | |
case 7: return set.__fds_bits.7 & mask != 0 | |
case 8: return set.__fds_bits.8 & mask != 0 | |
case 9: return set.__fds_bits.9 & mask != 0 | |
case 10: return set.__fds_bits.10 & mask != 0 | |
case 11: return set.__fds_bits.11 & mask != 0 | |
case 12: return set.__fds_bits.12 & mask != 0 | |
case 13: return set.__fds_bits.13 & mask != 0 | |
case 14: return set.__fds_bits.14 & mask != 0 | |
case 15: return set.__fds_bits.15 & mask != 0 | |
default: return false | |
} | |
#else | |
let intOffset = Int32(descriptor / 32) | |
let bitOffset = Int32(descriptor % 32) | |
let mask = Int32(1 << bitOffset) | |
switch intOffset { | |
case 0: return set.fds_bits.0 & mask != 0 | |
case 1: return set.fds_bits.1 & mask != 0 | |
case 2: return set.fds_bits.2 & mask != 0 | |
case 3: return set.fds_bits.3 & mask != 0 | |
case 4: return set.fds_bits.4 & mask != 0 | |
case 5: return set.fds_bits.5 & mask != 0 | |
case 6: return set.fds_bits.6 & mask != 0 | |
case 7: return set.fds_bits.7 & mask != 0 | |
case 8: return set.fds_bits.8 & mask != 0 | |
case 9: return set.fds_bits.9 & mask != 0 | |
case 10: return set.fds_bits.10 & mask != 0 | |
case 11: return set.fds_bits.11 & mask != 0 | |
case 12: return set.fds_bits.12 & mask != 0 | |
case 13: return set.fds_bits.13 & mask != 0 | |
case 14: return set.fds_bits.14 & mask != 0 | |
case 15: return set.fds_bits.15 & mask != 0 | |
case 16: return set.fds_bits.16 & mask != 0 | |
case 17: return set.fds_bits.17 & mask != 0 | |
case 18: return set.fds_bits.18 & mask != 0 | |
case 19: return set.fds_bits.19 & mask != 0 | |
case 20: return set.fds_bits.20 & mask != 0 | |
case 21: return set.fds_bits.21 & mask != 0 | |
case 22: return set.fds_bits.22 & mask != 0 | |
case 23: return set.fds_bits.23 & mask != 0 | |
case 24: return set.fds_bits.24 & mask != 0 | |
case 25: return set.fds_bits.25 & mask != 0 | |
case 26: return set.fds_bits.26 & mask != 0 | |
case 27: return set.fds_bits.27 & mask != 0 | |
case 28: return set.fds_bits.28 & mask != 0 | |
case 29: return set.fds_bits.29 & mask != 0 | |
case 30: return set.fds_bits.30 & mask != 0 | |
case 31: return set.fds_bits.31 & mask != 0 | |
default: return false | |
} | |
#endif | |
} | |
func fdSet(_ descriptor: Int32, _ set: inout fd_set) { | |
#if os(Linux) | |
let intOffset = Int(descriptor / 16) | |
let bitOffset = Int(descriptor % 16) | |
let mask = 1 << bitOffset | |
switch intOffset { | |
case 0: set.__fds_bits.0 = set.__fds_bits.0 | mask | |
case 1: set.__fds_bits.1 = set.__fds_bits.1 | mask | |
case 2: set.__fds_bits.2 = set.__fds_bits.2 | mask | |
case 3: set.__fds_bits.3 = set.__fds_bits.3 | mask | |
case 4: set.__fds_bits.4 = set.__fds_bits.4 | mask | |
case 5: set.__fds_bits.5 = set.__fds_bits.5 | mask | |
case 6: set.__fds_bits.6 = set.__fds_bits.6 | mask | |
case 7: set.__fds_bits.7 = set.__fds_bits.7 | mask | |
case 8: set.__fds_bits.8 = set.__fds_bits.8 | mask | |
case 9: set.__fds_bits.9 = set.__fds_bits.9 | mask | |
case 10: set.__fds_bits.10 = set.__fds_bits.10 | mask | |
case 11: set.__fds_bits.11 = set.__fds_bits.11 | mask | |
case 12: set.__fds_bits.12 = set.__fds_bits.12 | mask | |
case 13: set.__fds_bits.13 = set.__fds_bits.13 | mask | |
case 14: set.__fds_bits.14 = set.__fds_bits.14 | mask | |
case 15: set.__fds_bits.15 = set.__fds_bits.15 | mask | |
default: break | |
} | |
#else | |
let intOffset = Int32(descriptor / 16) | |
let bitOffset = Int32(descriptor % 16) | |
let mask: Int32 = 1 << bitOffset | |
switch intOffset { | |
case 0: set.fds_bits.0 = set.fds_bits.0 | mask | |
case 1: set.fds_bits.1 = set.fds_bits.1 | mask | |
case 2: set.fds_bits.2 = set.fds_bits.2 | mask | |
case 3: set.fds_bits.3 = set.fds_bits.3 | mask | |
case 4: set.fds_bits.4 = set.fds_bits.4 | mask | |
case 5: set.fds_bits.5 = set.fds_bits.5 | mask | |
case 6: set.fds_bits.6 = set.fds_bits.6 | mask | |
case 7: set.fds_bits.7 = set.fds_bits.7 | mask | |
case 8: set.fds_bits.8 = set.fds_bits.8 | mask | |
case 9: set.fds_bits.9 = set.fds_bits.9 | mask | |
case 10: set.fds_bits.10 = set.fds_bits.10 | mask | |
case 11: set.fds_bits.11 = set.fds_bits.11 | mask | |
case 12: set.fds_bits.12 = set.fds_bits.12 | mask | |
case 13: set.fds_bits.13 = set.fds_bits.13 | mask | |
case 14: set.fds_bits.14 = set.fds_bits.14 | mask | |
case 15: set.fds_bits.15 = set.fds_bits.15 | mask | |
default: break | |
} | |
#endif | |
} | |
extension FileHandle { | |
public var isDataAvailable: Bool { | |
var set = fd_set() | |
fdZero(&set) | |
var timeout: timeval = timeval.init(tv_sec: 0, tv_usec: 0) | |
fdSet(self.fileDescriptor, &set) | |
let result: Bool | |
switch select(4, &set, nil, nil, &timeout) { | |
case 1...: result = fdIsSet(self.fileDescriptor, &set) | |
default: result = false | |
} | |
return result | |
} | |
} |
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
// | |
// main.swift | |
// TestingAliveProcess | |
// | |
// Created by Seivan Heidari on 18/06/12. | |
// Copyright © 2018 Seivan Heidari. All rights reserved. | |
// | |
import Foundation | |
import CoreFoundation | |
import Dispatch | |
import SwiftProtobuf | |
extension Date { | |
func elapsedTime(to date: Date) -> String { | |
let attoseconds100 = date.timeIntervalSince(self) * 10000000000000 | |
switch attoseconds100 { | |
case 6048000000000000000...: | |
let weeks : Int = Int(attoseconds100 / 6048000000000000000) | |
return "\(weeks)w" + " " + "\(Int(attoseconds100 / 864000000000000000) - (weeks * 7))d" | |
case 864000000000000000...: | |
let days : Int = Int(attoseconds100 / 864000000000000000) | |
return "\(days)d" + " " + "\(Int(attoseconds100 / 36000000000000000) - (days * 24))h" | |
case 36000000000000000...: | |
let hours : Int = Int(attoseconds100 / 36000000000000000) | |
return "\(hours)h" + " " + "\(Int(attoseconds100 / 600000000000000) - (hours * 60))m" | |
case 600000000000000...: | |
let mins : Int = Int(attoseconds100 / 600000000000000) | |
return "\(mins)m" + " " + "\(Int(attoseconds100 / 10000000000000) - (mins * 60))s" | |
case 10000000000000...: | |
let secs : Int = Int(attoseconds100 / 10000000000000) | |
return "\(secs)s" + " " + "\(Int(attoseconds100 / 10000000000) - (secs * 1000))ms" | |
case 10000000000...: | |
let millisecs : Int = Int(attoseconds100 / 10000000000) | |
return "\(millisecs)ms" + " " + "\(Int(attoseconds100 / 10000000) - (millisecs * 1000))μs" | |
case 10000000...: | |
let microsecs : Int = Int(attoseconds100 / 10000000) | |
return "\(microsecs)μs" + " " + "\(Int(attoseconds100 / 10000) - (microsecs * 1000))ns" | |
case 10000...: | |
let nanosecs : Int = Int(attoseconds100 / 10000) | |
return "\(nanosecs)ns" + " " + "\(Int(attoseconds100 / 10) - (nanosecs * 1000))ps" | |
case 10...: | |
let picosecs : Int = Int(attoseconds100 / 10) | |
return "\(picosecs)ps" + " " + "\(Int(attoseconds100 / 0.01) - (picosecs * 1000))fs" | |
case 0.01...: | |
let femtosecs : Int = Int(attoseconds100 * 100) | |
return "\(femtosecs)fs" + " " + "\((Int(attoseconds100 / 0.001) - (femtosecs * 10)) * 100)as" | |
case 0.001...: | |
return "\(Int(attoseconds100 * 100000))as" | |
default: | |
return "Less than 100 attoseconds" | |
} | |
} | |
} | |
var shouldKeepRunning = true | |
var args = CommandLine.arguments | |
let packetOffset = MemoryLayout<UInt32>.size | |
protocol Messagable { | |
var content: String { get } | |
} | |
extension Messagable where Self: CustomDebugStringConvertible { | |
var content: String { return self.debugDescription } | |
} | |
extension GameMessage : Messagable {} | |
extension String : Messagable { | |
init(serializedData: Data) throws { | |
self.init(data: serializedData, encoding: .utf8)! | |
} | |
} | |
var messages = Array<Messagable>() | |
var existingData: Data? = nil | |
let reader = FileHandle.init(fileDescriptor: 3, closeOnDealloc: true) | |
let writer = FileHandle.init(fileDescriptor: 4, closeOnDealloc: true) | |
//let reader = FileHandle.standardInput | |
//let writer = FileHandle.standardOutput | |
//var flags = fcntl(reader.fileDescriptor, F_GETFL) | |
//_ = fcntl(reader.fileDescriptor, F_SETFL, flags | O_NONBLOCK) | |
extension Data { | |
var packetSize: UInt32 { return self.packetSize(at: 0, isBigEndian: true) } | |
func packetSize<T: FixedWidthInteger>(at index: Data.Index, isBigEndian: Bool) -> T { | |
let number: T = self[index..<index + MemoryLayout<T>.size].withUnsafeBytes { $0.pointee } | |
switch isBigEndian { | |
case true: return number.bigEndian | |
case false: return number.littleEndian | |
} | |
} | |
} | |
func createMessage(_ message: String) -> Data { | |
var text = message.data(using: .utf8)! | |
var count = UInt32(text.count).bigEndian | |
var pre = Data(bytes: &count, count: packetOffset) | |
pre.append(text) | |
return pre | |
} | |
func createMessage(_ data: Data) -> Data { | |
var count = UInt32(data.count).bigEndian | |
var pre = Data(bytes: &count, count: packetOffset) | |
pre.append(data) | |
return pre | |
} | |
func pushBackResponse(_ message: String) { | |
let response = try! GameMessage.with { | |
$0.log = message | |
}.serializedData() | |
writer.write(createMessage(response)) | |
} | |
func pushBackResponse(_ message: Data) { | |
writer.write(createMessage(message)) | |
} | |
func collectPackages(from input: Data, list: Array<Data> = []) -> (Array<Data>?, Data?) { | |
let data = input | |
let dataEndIndex = data.endIndex | |
// Need at least enough to read the size bytes | |
if data.count < packetOffset { return (list, data) } | |
//make failable, look at above snippet for ideas ^ | |
let sizeOfPackage: UInt32 = data.packetSize | |
//Make sure there is a size | |
guard sizeOfPackage > 0 else { return (list, data) } | |
// Offset the size package and read from there to the size. | |
let packageEndIndex = packetOffset + Int(sizeOfPackage) | |
//Make sure the data is larger or equal to the requested size | |
guard dataEndIndex >= packageEndIndex else { return (list, data) } | |
let package = data.subdata(in: packetOffset..<packageEndIndex) | |
let newList = [package] + list | |
let rest = data.subdata(in: packageEndIndex..<dataEndIndex) | |
guard package.count > 0 && rest.count > 0 else { return (newList, nil) } | |
return collectPackages(from: rest, list: newList) | |
} | |
func checkWithExisting(_ received: Data) { | |
guard received.count > 0 else { exit(0) } //EOF, shut down baby! | |
let data: Data | |
switch existingData { | |
case var existData?: | |
existData.append(received) | |
data = existData | |
case nil : data = received | |
} | |
let (maybeList, incompleteData) = collectPackages(from: data) | |
existingData = incompleteData | |
if let list = maybeList, list.isEmpty == false { | |
messages = messages + list.compactMap { try? GameMessage(serializedData: $0) } | |
} | |
} | |
//// NOT CALLED ON MAIN, RACE CONDITION, needs a lock. | |
//reader.readabilityHandler = { | |
//// let name = __dispatch_queue_get_label(nil) | |
//// let x = String(cString: name, encoding: .utf8) | |
//// print(x) | |
// checkWithExisting($0.availableData) | |
//} | |
let group = DispatchGroup() | |
while shouldKeepRunning { | |
group.enter() | |
let work = SystemWork() | |
work.work() | |
print("WORK DONE") | |
break | |
print("NOT BREAKING") | |
// Select + Block - disable flags! | |
if reader.isDataAvailable { | |
checkWithExisting( reader.availableData) | |
} | |
//NonBlock - don't forget flags! | |
// if let data = reader.nonBlockingAvailableData() { | |
// checkWithExisting( data) | |
// } | |
// // Select + NonBlock - don't forget flags! | |
// if reader.isDataAvailable { | |
// if let data = reader.nonBlockingAvailableData() { | |
// checkWithExisting( data) | |
// } | |
// } | |
// let x = (0..<10000).map { x in | |
// (0..<10000).map { y in | |
// x * y | |
// } | |
// } | |
// let _ = x.count | |
while let m = messages.popLast() { | |
switch (m as! GameMessage).type { | |
case .log(_)?: | |
break | |
case let .command(command)?: | |
switch command.type { | |
case let .request(request)?: | |
switch request.state { | |
case .start: | |
print("TEST") | |
case .end: | |
print("TEST") | |
case .pause: | |
print("TEST") | |
case .restart: | |
print("TEST") | |
case nil: | |
print("TEST") | |
case .UNRECOGNIZED(_): | |
print("TEST") | |
} | |
case let .response(response)?: | |
switch response.state { | |
case .start: | |
print("TEST") | |
case .end: | |
print("TEST") | |
case .pause: | |
print("TEST") | |
case .restart: | |
print("TEST") | |
case nil: | |
print("TEST") | |
case .UNRECOGNIZED(_): | |
print("TEST") | |
} | |
case nil: print("TEST") | |
} | |
case nil: print("TEST") | |
} | |
let response = try! GameMessage.with { | |
$0.log = "Responding to your message that contained \(m.content)" | |
}.serializedData() | |
// let values = [true, true, true, true, false, true] | |
// let vector = CFBitVectorCreateMutable( kCFAllocatorDefault, values.count) | |
// CFBitVectorSetCount(vector, values.count) | |
// print(vector) | |
// | |
// var sets = IndexSet() | |
// sets.insert(32) | |
// sets.insert(99999) | |
// print(sets.count) | |
// print(sets.rangeView.count) | |
// print("indexSet") | |
pushBackResponse(response) | |
} | |
usleep(2000) | |
// if messages.count >= 5000 { | |
// print("REACHED") | |
// messages.removeAll() | |
// | |
// } | |
group.leave() | |
} | |
_ = group.wait(timeout: DispatchTime.distantFuture) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment