mobilenativefoundation / kronos Goto Github PK
View Code? Open in Web Editor NEWElegant NTP date library in Swift
License: Apache License 2.0
Elegant NTP date library in Swift
License: Apache License 2.0
Looks like CFNetwork
is being used to handle the network communication layer and it has mysteriously been removed from the list of frameworks supported in watchOS. I'll be taking a stab at this functionality in my fork, but figured it was worth noting here incase you all have been thinking about it.
It does not appear that the podspec has been submitted to the Cocoapods repo.
We've had some intermittent crashes that seem to originate from the dateToNTPFormat
method in NTPPacket
. Specifically where Kronos appears to be casting the provided TimeInterval
to UInt32
like so: UInt32(time + kEpochDelta)
.
The stacktrace looks as follows:
EXC_BREAKPOINT:
0 X Swift runtime failure: Double value cannot be converted to UInt32 because the result would be greater than UInt32.max (NTPPacket.swift:153:23)
1 X specialized closure #1 in NTPClient.sendAsyncUDPQuery(to:port:timeout:completion:) (NTPClient.swift:155:34)
2 X closure #1 in NTPClient.sendAsyncUDPQuery(to:port:timeout:completion:) (<compiler-generated>)
3 CoreFoundation ___CFSocketPerformV0
4 CoreFoundation ___CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
5 CoreFoundation ___CFRunLoopDoSource0
6 CoreFoundation ___CFRunLoopDoSources0
7 CoreFoundation ___CFRunLoopRun
8 CoreFoundation _CFRunLoopRunSpecific
9 GraphicsServices _GSEventRunModal
10 UIKitCore -[UIApplication _run]
11 UIKitCore _UIApplicationMain
12 X main (AppDelegate.swift:26:7)
13 dyld start
Steps:
import Kronos
and Clock.sync()
Hi, so I have had full functioning usage of this library previously. But all of sudden, Clock.now always produces nil ONLY on Ipad, not on iphone! What could cause something like this?
when i use it in mac app development, during using
Clock.sync { date, offset in // This is the first sync (note that this is the fastest but not the // most accurate run print(date) }
it shows
networkd_settings_read_from_file Sandbox is preventing this process from reading networkd settings file at "/Library/Preferences/com.apple.networkd.plist", please add an exception.
i guess it means the library need network connection. However, the plist can't be found in mac
Could you give me more advices
I sometimes have problems with Clock.sync()
not returning a TimeInterval
in the completion
closure. After an analysis I found out that the problem lies in the NTPClient
in private func offset(from responses: [[NTPPacket]]) throws -> TimeInterval
. All server responses are filtered here by originTime
(which is afaik ok). Now it can happen that certain responses take longer than 10 seconds (= kMaximumResultDispersion
), especially if I use the default NTP server(s) time.apple.com
with the default 4 samples. If this happens with the last response, no TimeInterval
is returned. Although validate timeIntervals might have been returned beforehand. Is this done on purpose or would it also be possible to save the offsets in the sync()
function (Clock.swift
) and then return an average value at the end?
If I use the first
closure I always get a valid offset (maybe there are cases where this response is also filtered).
Is the most recent commit a working version of Kronos? I downloaded the pods but all of the Swift files have errors in them.
I am getting crash reports from NTPPacket, not a lot since there are thousand of users, but 10 in the last two weeks. Sometimes the user has been running the app for an hour without problems. It is also weird that the log points to line 20, which is empty (but that could be an error in the reporting).
MAIN THREAD - CRASHED
CoreFoundation CFAssertMismatchedTypeID
CoreFoundation CFRunLoopSourceInvalidate
CFNetwork CFNetServiceBrowserStopSearch
CoreFoundation CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
CoreFoundation __CFRunLoopDoSource0
CoreFoundation __CFRunLoopDoSources0
SprintTimer main NTPPacket.swift:20
libdyld.dylib start
hi everyone ๐
we are using Kronos
as a dependency in Datadog iOS SDK and we were wondering if you had any plans for distributing Kronos
as binary / xcframework
?
Hello Lyft ๐๐
I'm stepping across this project, as we're looking for NTP library. It looks great and does what we need with minimum code ๐. Although, I'm wondering if it's possible to specify multiple NTP hosts?
Kronos Android supports it:
val NTP_HOSTS = listOf("0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org")
// ..
ntpHosts: List<String> = NTP_HOSTS
but the iOS version seems to only accept single host:
pool: String = "time.apple.com"
Kronos is a dependency of our SDK we distribute via CocoaPods. When we build an XCFramework using xcodebuild
from the 14.3 command line tools and run pod lib lint
it fails with the following error:
Ld /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Binary/Kronos normal x86_64 (in target 'Kronos' from project 'Pods')
cd /var/folders/4t/7g326jh57pg0k71lf8fbhmf80000gn/T/CocoaPods-Lint-20230615-27046-inia4k-OurFrameworkName/Pods
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target x86_64-apple-ios8.0-simulator -dynamiclib -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator16.4.sdk -L/Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/EagerLinkingTBDs/Release-iphonesimulator -L/Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Products/Release-iphonesimulator/Kronos -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator16.4.sdk/usr/lib/swift -F/Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/EagerLinkingTBDs/Release-iphonesimulator -F/Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Products/Release-iphonesimulator/Kronos -filelist /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Kronos.LinkFileList -install_name @rpath/Kronos.framework/Kronos -Xlinker -rpath -Xlinker /usr/lib/swift -Xlinker -rpath -Xlinker @executable_path/Frameworks -Xlinker -rpath -Xlinker @loader_path/Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Kronos_lto.o -Xlinker -objc_abi_version -Xlinker 2 -fobjc-arc -fobjc-link-runtime -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Kronos.swiftmodule -framework Foundation -Xlinker -no_adhoc_codesign -compatibility_version 1 -current_version 1 -Xlinker -dependency_info -Xlinker /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Kronos_dependency_info.dat -o /Users/Jordan/Library/Developer/Xcode/DerivedData/App-gskrprtpdpsrsqehhmzigzstrfhu/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/Kronos.build/Objects-normal/x86_64/Binary/Kronos
ld: file not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)
/var/folders/4t/7g326jh57pg0k71lf8fbhmf80000gn/T/CocoaPods-Lint-20230615-27046-inia4k-OurFrameworkName/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 11.0 to 16.4.99. (in target 'Kronos' from project 'Pods')
Testing with `xcodebuild`.
-> OurFrameworkName (5.0.0)
- ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code.
- NOTE | [iOS] xcodebuild: Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 11.0 to 16.4.99. (in target 'Kronos' from project 'Pods')
Flutter had this same error (issue) and fixed it (pull request) by updating transitive dependencies to a minimum version of at least iOS 9. It seems Kronos needs to do the same. Explained in that PR, it happens because:
Xcode 14.3 (released March 30, 2023) stopped building automatic reference counted (ARC) code targeting < iOS 9 or < macOS 10.11 by removing a libarclite_* library from the toolchain that was needed to link for these older targets.
I also recommend filing issues with any pods you see hitting this to suggest they updated to a minimum of at least iOS 9 and macOS 10.11. For example openid/AppAuth-iOS#761
Just checking in on whether anyone is tackling or not. Happy to help.
It says:
error: root manifest not found
How does this behave when a network is not present, is slow or fails to complete request or user restarts app with no network.
Does clock.now
go out of sync and become unreliable?
Is the team interested in adding official Carthage support to the README?
Is it possible to make the library persist the last value on disk and restore it after an app restart?
My suggestion:
public class TimeFreeze : NSObject, NSCoding {
// NOTE: `adjustedTimestamp` is not an optional anymore
var adjustedTimestamp: TimeInterval { ... }
public required init?(coder aDecoder: NSCoder) {
guard
aDecoder.containsValue(forKey: "uptime"),
aDecoder.containsValue(forKey: "offset"),
aDecoder.containsValue(forKey: "timestamp")
else { return nil }
self.uptime = aDecoder.decodeDouble(forKey: "uptime")
self.timestamp = aDecoder.decodeDouble(forKey: "offset")
self.offset = aDecoder.decodeDouble(forKey: "timestamp")
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(self.uptime, forKey: "uptime")
aCoder.encode(self.timestamp, forKey: "timestamp")
aCoder.encode(self.offset, forKey: "offset")
}
}
public struct Clock {
// NOTE: `private(set)`
public private(set) static var stableTime: TimeFreeze?
public static func restore(from other: TimeFreeze) {
guard self.stableTime == nil || (self.stableTime!.adjustedTimestamp < other.adjustedTimestamp) else { return }
self.stableTime = other
}
}
I am getting warnings for the three append functions in Data+Bytes, e.g.
mutating func append(byte data: Int8) {
var data = data
self.append(UnsafeBufferPointer(start: &data, count: 1))
}
Warning:
"Initialization of 'UnsafeBufferPointer' results in a dangling buffer pointer
Implicit argument conversion from 'Int8' to 'UnsafePointer?' produces a pointer valid only for the duration of the call to 'init(start:count:)
Use 'withUnsafePointer' in order to explicitly convert argument to pointer valid for a defined scope"
I have limited experience with UnsafePointers so I am unsure how to correct this. Does anyone have a tip?
Curious to know if there are mechanisms in place for reachability changes
Hi,
My team is considering to use Kronos for our financial application.
However, I have a few questions before I can make a decision:
I get the error:
"Building for Mac Catalyst, but the linked framework 'Kronos.framework' was built for iOS + iOS Simulator."
I have installed it with Carthage. Is there a simple way to fix this or should I add it manually?
When using SPM, the library is imported as static. Will you add support for importing as dynamic?
Hello,
if the lib is inclued in an app running on iOS 14 an authorisation is asked at launch in a system popup :
"NAME_OF_YOUR_APP" would like to find and connect to devices on your local network.
This app will be able to discover and connect to devices on the networks you use.
Don't allow - OK
This does not appear on Wi-Fi, it is displayed only if the phone is on cellular network like 4G.
This is triggered by Clock.sync()
Why Kronos wants to use local network ? How to avoid this popup in any case ?
Thanks
Has there been any discussion around introducing an async/await
api around Clock.now
? Would be really nice to have syntactically!
When my app is launched, I want to create a
struct Log {
...
let ts: Date
...
}
and also create them periodically onwards, stored to a file that gets uploaded to a server every couple minutes.
If I use Kronos, I understand the time I initially get will be not be accurate, so the first x logs created will have inaccurate time, is there a straightforward way to update the logs with a more accurate time after the Clock.sync
callbacks all call back?
Is possible to get an estimate of the accuracy from the sync call? E.g. based on the network latency.
WARNING: ThreadSanitizer: data race (pid=97366)
Read of size 8 at 0x0001164e9888 by thread T4:
#0 static Clock.annotatedNow.getter <null>:2 (Kronos:x86_64+0x26a76ca)
#1 static Clock.now.getter <null>:2 (Kronos:x86_64+0x26a747d)
Previous write of size 8 at 0x0001164e9888 by main thread:
#0 static Clock.stableTime.setter <null>:2 (Kronos:x86_64+0x26a6dcf)
#1 closure #1 in static Clock.sync(from:samples:first:completion:) <null>:2 (Kronos:x86_64+0x26a827e)
#2 partial apply for closure #1 in static Clock.sync(from:samples:first:completion:) <null>:2 (Kronos:x86_64+0x26a86b5)
#3 $defer #1 () in closure #1 in closure #1 in NTPClient.query(pool:version:port:numberOfSamples:maximumServers:timeout:progress:) <null>:2 (Kronos:x86_64+0x26b7cf7)
#4 closure #1 in closure #1 in NTPClient.query(pool:version:port:numberOfSamples:maximumServers:timeout:progress:) <null>:2 (Kronos:x86_64+0x26b783c)
#5 partial apply for closure #1 in closure #1 in NTPClient.query(pool:version:port:numberOfSamples:maximumServers:timeout:progress:) <null>:2 (Kronos:x86_64+0x26bd6f8)
#6 closure #1 in NTPClient.query(ip:port:version:timeout:numberOfSamples:completion:) <null>:2 (Kronos:x86_64+0x26b9af7)
#7 partial apply for closure #1 in NTPClient.query(ip:port:version:timeout:numberOfSamples:completion:) <null>:2 (Kronos:x86_64+0x26bdb8e)
#8 thunk for @escaping @callee_guaranteed (@guaranteed Data?, @unowned Double) -> () <null>:2 (Kronos:x86_64+0x26ba39d)
#9 closure #1 in NTPClient.sendAsyncUDPQuery(to:port:timeout:completion:) <null>:2 (Kronos:x86_64+0x26bd0dd)
#10 @objc closure #1 in NTPClient.sendAsyncUDPQuery(to:port:timeout:completion:) <null>:2 (Kronos:x86_64+0x26bd1f3)
#11 __CFSocketPerformV0 <null>:2 (CoreFoundation:x86_64+0x92fd9)
#12 start <null>:2 (libdyld.dylib:x86_64+0x1408)
Location is global 'static Clock.stableTime' at 0x0001164e9888 (Kronos+0x000005b96888)
Thread T4 (tid=1302869, running) is a GCD worker thread
Because the version was bumped on the Podspec after 4.0.1 was released, the 4.0.1 tag doesn't contain that bump and so Xcode warns that Kronos needs to be converted. Either the tag should be updated to point to commit 5b05b5c or a new tag and Podspec bump should be done.
In the WWDC23, Apple announced new changes regarding privacy. Now, apps and third parties will have to include a file called a Privacy Manifest file.
After digging into the Kronos project, I've just observed that it's using UserDefaults API here. According to Apple documentation, if the SDK uses the UserDefaults API, then it must include a PrivacyInfo.xcprivacy
file mentioning any approved reason for why it's used. I think in this case, the reason would be: CA92.1
.
My Podfile looks like this
#Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
target 'OHOBPoc' do
#Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'Kronos'
#Pods for OHOBPoc
end
Kronos (0.2.2) got installed
Can you please help me on this
I have tried setting up NTP server on a Windows PC (WinPC) and a Raspberry Pi (RPi) and noticed that the framework works well syncing time with WinPC but fail to do so when setting RPi as the server.
I simply run "Clock.sync(from: (IP of WinPC/RPi))" during initialization of the app and use "Clock.now" to get server time. When setting the IP of WinPC, it works, while setting IP of RPi doesn't.
The way I set up NTP server on RPi is by adding following lines to /etc/ntp.conf
server 127.127.1.0
fudge 127.127.1.0 stratum 10
restrict 192.168.0.24 mask 255.255.255.0 nomodify
I have tested on a Macbook Pro with command "ntpdate -u (IP of RPi)" to sync time from RPi and it works well, which proves that the NTP server on RPi is running.
I would appreciate if you could provide any help/comment on this issue. Thank you.
It looks like Clock.sync() does not work if I have WiFi off and cellular data (LTE) on. In particular, the "first:" and "completion:" blocks never get called. It works if WiFi is on.
Am I missing something? It seems rather odd.
Hello everyone,
I would like to build an app that records frames and depth images throughout an AR session.
For this purpose I need to have the time synchronized as best as possible.
My question is, whether there is a better way to get the ARFrame timestamps synced than to call sync before recording and safe the offset to add it later to the recorded internal timestamps.
Thanks already for your help!
Calling sync() from a background thread does not seem to work - neither the first or full completion handlers ever get called, not even after the timeout duration. Running the call from the main thread resolves the issue.
Might be worth documenting, or handling a little better?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.