Commit
This commit is contained in:
13
Carthage/Checkouts/TrueTime.swift/.github/pull_request_template.md
vendored
Normal file
13
Carthage/Checkouts/TrueTime.swift/.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
### What did you change and why?
|
||||
|
||||
|
||||
### Potential risks introduced?
|
||||
|
||||
|
||||
### What tests were performed (include steps)?
|
||||
|
||||
|
||||
### Checklist
|
||||
|
||||
- [ ] Unit/UI tests have been written (if necessary)
|
||||
- [ ] Manually tested
|
63
Carthage/Checkouts/TrueTime.swift/.gitignore
vendored
Normal file
63
Carthage/Checkouts/TrueTime.swift/.gitignore
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
# Xcode
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
.build/
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
Carthage/Checkouts
|
||||
Carthage/Build
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
xcodebuild.log
|
4
Carthage/Checkouts/TrueTime.swift/.gitmodules
vendored
Normal file
4
Carthage/Checkouts/TrueTime.swift/.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "External/xcconfigs"]
|
||||
path = External/xcconfigs
|
||||
url = https://github.com/jspahrsummers/xcconfigs.git
|
||||
branch = 0.9
|
1
Carthage/Checkouts/TrueTime.swift/.swift-version
vendored
Normal file
1
Carthage/Checkouts/TrueTime.swift/.swift-version
vendored
Normal file
@ -0,0 +1 @@
|
||||
5.0
|
3
Carthage/Checkouts/TrueTime.swift/.swiftlint.yml
vendored
Normal file
3
Carthage/Checkouts/TrueTime.swift/.swiftlint.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
disabled_rules:
|
||||
- identifier_name
|
||||
- switch_case_alignment
|
19
Carthage/Checkouts/TrueTime.swift/.travis.yml
vendored
Normal file
19
Carthage/Checkouts/TrueTime.swift/.travis.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
osx_image: xcode10.2
|
||||
language: objective-c
|
||||
env:
|
||||
matrix:
|
||||
- PLATFORM=iOS SDK=iphonesimulator SCHEME=TrueTime-iOS DESTINATION="platform=iOS Simulator,name=iPhone 6,OS=10.0"
|
||||
- PLATFORM=Mac SDK=macosx SCHEME=TrueTime-Mac DESTINATION="platform=macOS"
|
||||
- PLATFORM=tvOS SDK=appletvsimulator SCHEME=TrueTime-tvOS DESTINATION="platform=tvOS Simulator,name=Apple TV 1080p,OS=10.0"
|
||||
install:
|
||||
- brew remove swiftlint --force || true
|
||||
- brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8d6cbc8/Formula/swiftlint.rb
|
||||
- brew remove carthage --force || true
|
||||
- brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/75d2a4a/Formula/carthage.rb
|
||||
- gem install xcpretty
|
||||
- carthage bootstrap --platform "$PLATFORM" --cache-builds --no-use-binaries --toolchain com.apple.dt.toolchain.Swift_3_1
|
||||
script:
|
||||
- Scripts/test
|
||||
cache:
|
||||
directories:
|
||||
- Carthage/Build
|
107
Carthage/Checkouts/TrueTime.swift/CHANGELOG.md
vendored
Normal file
107
Carthage/Checkouts/TrueTime.swift/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
`TrueTime.swift` adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [5.1.0](https://github.com/instacart/TrueTime.swift/releases/tag/5.1.0)
|
||||
|
||||
- Changed: `CTrueTime` is now embeded in the project to avoid issues with Carthage.
|
||||
|
||||
## [5.0.3](https://github.com/instacart/TrueTime.swift/releases/tag/5.0.2)
|
||||
|
||||
- Fixed: Resolved race condition crash by removing unnecessary retain/release.
|
||||
|
||||
## [5.0.2](https://github.com/instacart/TrueTime.swift/releases/tag/5.0.2)
|
||||
|
||||
- Changed: Swift 5 support and use of built-in `Result` type.
|
||||
|
||||
## [5.0.1](https://github.com/instacart/TrueTime.swift/releases/tag/5.0.1)
|
||||
|
||||
- Fixed: `EXC_BAD_ACCESS` Crash.
|
||||
|
||||
## [5.0.0](https://github.com/instacart/TrueTime.swift/releases/tag/5.0.0)
|
||||
|
||||
- Added: Swift 4 support.
|
||||
- Added: Exposed missing methods via Objective-C bridging.
|
||||
- Fixed: Addressed issue with poll interval not being handled.
|
||||
- Fixed: Addressed issue with resuming after pausing.
|
||||
- Changed: Dropped support for Swift 3.
|
||||
- Changed: Updated pool parameter in `TrueTime.start` to take an explicit
|
||||
string an port instead of a URL.
|
||||
|
||||
## [4.1.5](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.5)
|
||||
|
||||
- Fixed: Addressed issue with poll interval not being handled.
|
||||
|
||||
## [4.1.4](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.4)
|
||||
|
||||
- Fixed: Addressed casting issue with latest Xcode.
|
||||
|
||||
## [4.1.3](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.3)
|
||||
|
||||
- Fixed: Improved compile times when building from scratch.
|
||||
- Fixed: Exposed uptime interval for reporting.
|
||||
- Fixed: Updated dependencies to latest versions.
|
||||
|
||||
## [4.1.2](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.2)
|
||||
|
||||
- Fixed: Addressed warning when building with Swift 3.1.
|
||||
|
||||
## [4.1.1](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.1)
|
||||
|
||||
- Fixed: Addressed issue building project with latest swiftlint installed.
|
||||
|
||||
## [4.1.0](https://github.com/instacart/TrueTime.swift/releases/tag/4.1.0)
|
||||
|
||||
- Added: Now posting notification when reference time gets updated
|
||||
- Fixed: Fixed crash when receiving empty packets from certain hosts.
|
||||
|
||||
## [4.0.0](https://github.com/instacart/TrueTime.swift/releases/tag/4.0.0)
|
||||
|
||||
- Added: Swift 3 support.
|
||||
- Added: Support for configuring polling interval.
|
||||
- Changed: `retrieveReferenceTime` has been renamed to `fetchIfNeeded`.
|
||||
- Changed: Dropped support for Mac OS 10.9.
|
||||
|
||||
## [3.1.1](https://github.com/instacart/TrueTime.swift/releases/tag/3.1.1)
|
||||
|
||||
- Fixed: Addressed issue building project with latest swiftlint installed.
|
||||
|
||||
## [3.1.0](https://github.com/instacart/TrueTime.swift/releases/tag/3.1.0)
|
||||
|
||||
- Added: Now supporting CocoaPods.
|
||||
|
||||
## [3.0.0](https://github.com/instacart/TrueTime.swift/releases/tag/3.0.0)
|
||||
|
||||
- Added: Now polls at regular intervals and automatically updates reference
|
||||
times.
|
||||
- Fixed: Addressed assertion getting hit on certain devices when requesting
|
||||
network time.
|
||||
|
||||
## [2.1.1](https://github.com/instacart/TrueTime.swift/releases/tag/2.1.1)
|
||||
|
||||
- Fixed: Addressed memory leak due to long interpolated strings in Swift 2.3.
|
||||
- Fixed: Updated dispersion check and uptime function for more accurate times.
|
||||
|
||||
## [2.1.0](https://github.com/instacart/TrueTime.swift/releases/tag/2.1.0)
|
||||
|
||||
- Added: Now supporting full NTP integration.
|
||||
- Fixed: Fixed rare crash when resolving hosts.
|
||||
|
||||
## [2.0.0](https://github.com/instacart/TrueTime.swift/releases/tag/2.0.0)
|
||||
|
||||
- Added: Now supporting Xcode 8 and Swift 2.3.
|
||||
- Fixed: Fixed bundle identifier for tvOS framework.
|
||||
|
||||
## [1.1.0](https://github.com/instacart/TrueTime.swift/releases/tag/1.1.0)
|
||||
|
||||
- Fixed: Updated guard for outlier server responses to be more stringent.
|
||||
- Added: IPv6 support.
|
||||
|
||||
## [1.0.1](https://github.com/instacart/TrueTime.swift/releases/tag/1.0.1)
|
||||
|
||||
- Fixed: Addresses issue when cloning submodules.
|
||||
|
||||
## [1.0.0](https://github.com/instacart/TrueTime.swift/releases/tag/1.0.0)
|
||||
|
||||
- Initial release
|
77
Carthage/Checkouts/TrueTime.swift/CODE_OF_CONDUCT.md
vendored
Normal file
77
Carthage/Checkouts/TrueTime.swift/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
|
0
Carthage/Checkouts/TrueTime.swift/Cartfile
vendored
Normal file
0
Carthage/Checkouts/TrueTime.swift/Cartfile
vendored
Normal file
3
Carthage/Checkouts/TrueTime.swift/Cartfile.private
vendored
Normal file
3
Carthage/Checkouts/TrueTime.swift/Cartfile.private
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
github "Quick/Nimble"
|
||||
github "Quick/Quick"
|
||||
github "typelift/SwiftCheck"
|
3
Carthage/Checkouts/TrueTime.swift/Cartfile.resolved
vendored
Normal file
3
Carthage/Checkouts/TrueTime.swift/Cartfile.resolved
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
github "Quick/Nimble" "v8.0.1"
|
||||
github "Quick/Quick" "v2.1.0"
|
||||
github "typelift/SwiftCheck" "0.12.0"
|
26
Carthage/Checkouts/TrueTime.swift/Examples/iOS/AppDelegate.swift
vendored
Normal file
26
Carthage/Checkouts/TrueTime.swift/Examples/iOS/AppDelegate.swift
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// NTPExample
|
||||
//
|
||||
// Created by Michael Sanders on 7/9/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TrueTime
|
||||
|
||||
@UIApplicationMain
|
||||
final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
TrueTimeClient.sharedInstance.start()
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window?.backgroundColor = .white
|
||||
window?.makeKeyAndVisible()
|
||||
window?.rootViewController = ExampleViewController()
|
||||
return true
|
||||
}
|
||||
}
|
93
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
vendored
Normal file
93
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
29
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Bridging.m
vendored
Normal file
29
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Bridging.m
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Bridging.m
|
||||
// TrueTime-iOS
|
||||
//
|
||||
// Created by Michael Sanders on 1/2/18.
|
||||
// Copyright © 2018 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
@import TrueTime;
|
||||
|
||||
@interface Bridging : NSObject
|
||||
@end
|
||||
|
||||
@implementation Bridging
|
||||
|
||||
- (void)testBridging {
|
||||
TrueTimeClient *client = [TrueTimeClient sharedInstance];
|
||||
[client startWithPool:@[(id)[NSURL URLWithString:@"time.apple.com"]] port: 123];
|
||||
|
||||
NSDate *now = [[client referenceTime] now];
|
||||
NSLog(@"True time: %@", now);
|
||||
[client fetchIfNeededWithSuccess:^(NTPReferenceTime *referenceTime) {
|
||||
NSLog(@"True time: %@", [referenceTime now]);
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"Error! %@", error);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
BIN
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Default-568h@2x.png
vendored
Normal file
BIN
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Default-568h@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
43
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Info.plist
vendored
Normal file
43
Carthage/Checkouts/TrueTime.swift/Examples/iOS/Info.plist
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
98
Carthage/Checkouts/TrueTime.swift/Examples/iOS/ViewController.swift
vendored
Normal file
98
Carthage/Checkouts/TrueTime.swift/Examples/iOS/ViewController.swift
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 10/26/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TrueTime
|
||||
|
||||
final class ExampleViewController: UIViewController {
|
||||
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
|
||||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(startTimer),
|
||||
name: UIApplication.didBecomeActiveNotification,
|
||||
object: nil
|
||||
)
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(cancelTimer),
|
||||
name: UIApplication.willResignActiveNotification,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
label.frame = view.bounds.insetBy(dx: 15, dy: 15)
|
||||
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
view.addSubview(label)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
refresh()
|
||||
startTimer()
|
||||
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
cancelTimer()
|
||||
}
|
||||
|
||||
fileprivate var referenceTime: ReferenceTime?
|
||||
fileprivate var timer: Timer?
|
||||
fileprivate lazy var label: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = .black
|
||||
label.textAlignment = .center
|
||||
label.font = .systemFont(ofSize: 14)
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
}
|
||||
|
||||
private extension ExampleViewController {
|
||||
@objc func startTimer() {
|
||||
timer = .scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] _ in
|
||||
self?.tick()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func cancelTimer() {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
|
||||
func tick() {
|
||||
if let referenceTime = referenceTime {
|
||||
let trueTime = referenceTime.now()
|
||||
label.text = "\(trueTime)\n\n\(referenceTime)"
|
||||
}
|
||||
}
|
||||
|
||||
func refresh() {
|
||||
TrueTimeClient.sharedInstance.fetchIfNeeded { result in
|
||||
switch result {
|
||||
case let .success(referenceTime):
|
||||
self.referenceTime = referenceTime
|
||||
print("Got network time! \(referenceTime)")
|
||||
case let .failure(error):
|
||||
print("Error! \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/.gitignore
vendored
Normal file
1
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
Carthage/Build
|
179
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Common.xcconfig
vendored
Normal file
179
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Common.xcconfig
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
//
|
||||
// This file defines common settings that should be enabled for every new
|
||||
// project. Typically, you want to use Debug, Release, or a similar variant
|
||||
// instead.
|
||||
//
|
||||
|
||||
// Disable legacy-compatible header searching
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
||||
|
||||
// Architectures to build
|
||||
ARCHS = $(ARCHS_STANDARD)
|
||||
|
||||
// Whether to warn when a floating-point value is used as a loop counter
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
|
||||
|
||||
// Whether to warn about use of rand() and random() being used instead of arc4random()
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
|
||||
|
||||
// Whether to warn about strcpy() and strcat()
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
|
||||
|
||||
// Whether to enable module imports
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
// Enable ARC
|
||||
CLANG_ENABLE_OBJC_ARC = YES
|
||||
|
||||
// Warn about implicit conversions to boolean values that are suspicious.
|
||||
// For example, writing 'if (foo)' with 'foo' being the name a function will trigger a warning.
|
||||
CLANG_WARN_BOOL_CONVERSION = YES
|
||||
|
||||
// Warn about implicit conversions of constant values that cause the constant value to change,
|
||||
// either through a loss of precision, or entirely in its meaning.
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES
|
||||
|
||||
// Whether to warn when overriding deprecated methods
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
|
||||
|
||||
// Warn about direct accesses to the Objective-C 'isa' pointer instead of using a runtime API.
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
|
||||
|
||||
// Warn about declaring the same method more than once within the same @interface.
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
|
||||
|
||||
// Warn about loop bodies that are suspiciously empty.
|
||||
CLANG_WARN_EMPTY_BODY = YES
|
||||
|
||||
// Warn about implicit conversions between different kinds of enum values.
|
||||
// For example, this can catch issues when using the wrong enum flag as an argument to a function or method.
|
||||
CLANG_WARN_ENUM_CONVERSION = YES
|
||||
|
||||
// Whether to warn on implicit conversions between signed/unsigned types
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
|
||||
|
||||
// Warn about implicit conversions between pointers and integers.
|
||||
// For example, this can catch issues when one incorrectly intermixes using NSNumbers and raw integers.
|
||||
CLANG_WARN_INT_CONVERSION = YES
|
||||
|
||||
// Don't warn about repeatedly using a weak reference without assigning the weak reference to a strong reference. Too many false positives.
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO
|
||||
|
||||
// Warn about classes that unintentionally do not subclass a root class (such as NSObject).
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
|
||||
|
||||
// Whether to warn on suspicious implicit conversions
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
|
||||
|
||||
// Warn about potentially unreachable code
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES
|
||||
|
||||
// The format of debugging symbols
|
||||
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
|
||||
|
||||
// Whether to compile assertions in
|
||||
ENABLE_NS_ASSERTIONS = YES
|
||||
|
||||
// Whether to require objc_msgSend to be cast before invocation
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES
|
||||
|
||||
// Which C variant to use
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99
|
||||
|
||||
// Whether to enable exceptions for Objective-C
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES
|
||||
|
||||
// Whether to generate debugging symbols
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES
|
||||
|
||||
// Whether to precompile the prefix header (if one is specified)
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES
|
||||
|
||||
// Whether to enable strict aliasing, meaning that two pointers of different
|
||||
// types (other than void * or any id type) cannot point to the same memory
|
||||
// location
|
||||
GCC_STRICT_ALIASING = YES
|
||||
|
||||
// Whether symbols not explicitly exported are hidden by default (this primarily
|
||||
// only affects C++ code)
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO
|
||||
|
||||
// Whether static variables are thread-safe by default
|
||||
GCC_THREADSAFE_STATICS = NO
|
||||
|
||||
// Which compiler to use
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0
|
||||
|
||||
// Whether warnings are treated as errors
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES
|
||||
|
||||
// Whether to warn about 64-bit values being implicitly shortened to 32 bits
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
|
||||
// Whether to warn about fields missing from structure initializers (only if
|
||||
// designated initializers aren't used)
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
|
||||
|
||||
// Whether to warn about missing function prototypes
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO
|
||||
|
||||
// Whether to warn about implicit conversions in the signedness of the type
|
||||
// a pointer is pointing to (e.g., 'int *' getting converted to 'unsigned int *')
|
||||
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
|
||||
|
||||
// Whether to warn when the value returned from a function/method/block does not
|
||||
// match its return type
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
|
||||
|
||||
// Whether to warn on a class not implementing all the required methods of
|
||||
// a protocol it declares conformance to
|
||||
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES
|
||||
|
||||
// Whether to warn when switching on an enum value, and all possibilities are
|
||||
// not accounted for
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
|
||||
|
||||
// Whether to warn about the use of four-character constants
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
|
||||
|
||||
// Whether to warn about an aggregate data type's initializer not being fully
|
||||
// bracketed (e.g., array initializer syntax)
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
|
||||
|
||||
// Whether to warn about missing braces or parentheses that make the meaning of
|
||||
// the code ambiguous
|
||||
GCC_WARN_MISSING_PARENTHESES = YES
|
||||
|
||||
// Whether to warn about unsafe comparisons between values of different
|
||||
// signedness
|
||||
GCC_WARN_SIGN_COMPARE = YES
|
||||
|
||||
// Whether to warn about the arguments to printf-style functions not matching
|
||||
// the format specifiers
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
|
||||
|
||||
// Warn if a "@selector(...)" expression referring to an undeclared selector is found
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES
|
||||
|
||||
// Warn if a variable might be clobbered by a setjmp call or if an automatic variable is used without prior initialization.
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES
|
||||
|
||||
// Whether to warn about static functions that are unused
|
||||
GCC_WARN_UNUSED_FUNCTION = YES
|
||||
|
||||
// Whether to warn about labels that are unused
|
||||
GCC_WARN_UNUSED_LABEL = YES
|
||||
|
||||
// Whether to warn about variables that are never used
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
|
||||
// Whether to run the static analyzer with every build
|
||||
RUN_CLANG_STATIC_ANALYZER = YES
|
||||
|
||||
// Don't treat unknown warnings as errors, and disable GCC compatibility warnings and unused static const variable warnings
|
||||
WARNING_CFLAGS = -Wno-error=unknown-warning-option -Wno-gcc-compat -Wno-unused-const-variable -Wno-nullability-completeness
|
||||
|
||||
// This setting is on for new projects as of Xcode ~6.3, though it is still not
|
||||
// the default. It warns if the same variable is declared in two binaries that
|
||||
// are linked together.
|
||||
GCC_NO_COMMON_BLOCKS = YES
|
43
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Debug.xcconfig
vendored
Normal file
43
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Debug.xcconfig
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// This file defines the base configuration for a Debug build of any project.
|
||||
// This should be set at the project level for the Debug configuration.
|
||||
//
|
||||
|
||||
#include "../Common.xcconfig"
|
||||
|
||||
// Whether to strip debugging symbols when copying resources (like included
|
||||
// binaries)
|
||||
COPY_PHASE_STRIP = NO
|
||||
|
||||
// The optimization level (0, 1, 2, 3, s) for the produced binary
|
||||
GCC_OPTIMIZATION_LEVEL = 0
|
||||
|
||||
// Preproccessor definitions to apply to each file compiled
|
||||
GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1
|
||||
|
||||
// Whether to enable link-time optimizations (such as inlining across translation
|
||||
// units)
|
||||
LLVM_LTO = NO
|
||||
|
||||
// Whether to only build the active architecture
|
||||
ONLY_ACTIVE_ARCH = YES
|
||||
|
||||
// Other compiler flags
|
||||
//
|
||||
// These settings catch some errors in integer arithmetic
|
||||
OTHER_CFLAGS = -ftrapv
|
||||
|
||||
// Other flags to pass to the Swift compiler
|
||||
//
|
||||
// This enables conditional compilation with #if DEBUG
|
||||
OTHER_SWIFT_FLAGS = -D DEBUG
|
||||
|
||||
// Whether to strip debugging symbols when copying the built product to its
|
||||
// final installation location
|
||||
STRIP_INSTALLED_PRODUCT = NO
|
||||
|
||||
// The optimization level (-Onone, -O, -Ofast) for the produced Swift binary
|
||||
SWIFT_OPTIMIZATION_LEVEL = -Onone
|
||||
|
||||
// Disable Developer ID timestamping
|
||||
OTHER_CODE_SIGN_FLAGS = --timestamp=none
|
27
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Profile.xcconfig
vendored
Normal file
27
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Profile.xcconfig
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// This file defines the base configuration for an optional profiling-specific
|
||||
// build of any project. To use these settings, create a Profile configuration
|
||||
// in your project, and use this file at the project level for the new
|
||||
// configuration.
|
||||
//
|
||||
|
||||
// based on the Release configuration, with some stuff related to debugging
|
||||
// symbols re-enabled
|
||||
#include "Release.xcconfig"
|
||||
|
||||
// Whether to strip debugging symbols when copying resources (like included
|
||||
// binaries)
|
||||
COPY_PHASE_STRIP = NO
|
||||
|
||||
// Whether to only build the active architecture
|
||||
ONLY_ACTIVE_ARCH = YES
|
||||
|
||||
// Whether to strip debugging symbols when copying the built product to its
|
||||
// final installation location
|
||||
STRIP_INSTALLED_PRODUCT = NO
|
||||
|
||||
// Whether to perform App Store validation checks
|
||||
VALIDATE_PRODUCT = NO
|
||||
|
||||
// Disable Developer ID timestamping
|
||||
OTHER_CODE_SIGN_FLAGS = --timestamp=none
|
34
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Release.xcconfig
vendored
Normal file
34
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Release.xcconfig
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// This file defines the base configuration for a Release build of any project.
|
||||
// This should be set at the project level for the Release configuration.
|
||||
//
|
||||
|
||||
#include "../Common.xcconfig"
|
||||
|
||||
// Whether to strip debugging symbols when copying resources (like included
|
||||
// binaries)
|
||||
COPY_PHASE_STRIP = YES
|
||||
|
||||
// The optimization level (0, 1, 2, 3, s) for the produced binary
|
||||
GCC_OPTIMIZATION_LEVEL = s
|
||||
|
||||
// Preproccessor definitions to apply to each file compiled
|
||||
GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1
|
||||
|
||||
// Whether to enable link-time optimizations (such as inlining across translation
|
||||
// units)
|
||||
LLVM_LTO = NO
|
||||
|
||||
// Whether to only build the active architecture
|
||||
ONLY_ACTIVE_ARCH = NO
|
||||
|
||||
// Whether to strip debugging symbols when copying the built product to its
|
||||
// final installation location
|
||||
STRIP_INSTALLED_PRODUCT = YES
|
||||
|
||||
// The optimization level (-Onone, -O, -Owholemodule) for the produced Swift binary
|
||||
SWIFT_OPTIMIZATION_LEVEL = -Owholemodule
|
||||
|
||||
// Whether to perform App Store validation checks
|
||||
VALIDATE_PRODUCT = YES
|
||||
|
10
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Test.xcconfig
vendored
Normal file
10
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Configurations/Test.xcconfig
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// This file defines the base configuration for a Test build of any project.
|
||||
// This should be set at the project level for the Test configuration.
|
||||
//
|
||||
|
||||
#include "Debug.xcconfig"
|
||||
|
||||
// Sandboxed apps can't be unit tested since they can't load some random
|
||||
// external bundle. So we disable sandboxing for testing.
|
||||
CODE_SIGN_ENTITLEMENTS =
|
12
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/Application.xcconfig
vendored
Normal file
12
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/Application.xcconfig
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for an application. Typically, you want to use a platform-specific variant
|
||||
// instead.
|
||||
//
|
||||
|
||||
// Whether to strip out code that isn't called from anywhere
|
||||
DEAD_CODE_STRIPPING = NO
|
||||
|
||||
// Sets the @rpath for the application such that it can include frameworks in
|
||||
// the application bundle (inside the "Frameworks" folder)
|
||||
LD_RUNPATH_SEARCH_PATHS = @executable_path/../Frameworks @loader_path/../Frameworks @executable_path/Frameworks
|
32
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/Framework.xcconfig
vendored
Normal file
32
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/Framework.xcconfig
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a framework. Typically, you want to use a platform-specific variant
|
||||
// instead.
|
||||
//
|
||||
|
||||
// Whether to strip out code that isn't called from anywhere
|
||||
DEAD_CODE_STRIPPING = NO
|
||||
|
||||
// Whether this framework should define an LLVM module
|
||||
DEFINES_MODULE = YES
|
||||
|
||||
// Whether function calls should be position-dependent (should always be
|
||||
// disabled for library code)
|
||||
GCC_DYNAMIC_NO_PIC = NO
|
||||
|
||||
// Default frameworks to the name of the project, instead of any
|
||||
// platform-specific target
|
||||
PRODUCT_NAME = $(PROJECT_NAME)
|
||||
|
||||
// Enables the framework to be included from any location as long as the
|
||||
// loader’s runpath search paths includes it. For example from an application
|
||||
// bundle (inside the "Frameworks" folder) or shared folder
|
||||
INSTALL_PATH = @rpath
|
||||
LD_DYLIB_INSTALL_NAME = @rpath/$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/$(PRODUCT_NAME)
|
||||
SKIP_INSTALL = YES
|
||||
|
||||
// Disallows use of APIs that are not available
|
||||
// to app extensions and linking to frameworks
|
||||
// that have not been built with this setting enabled.
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
32
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/StaticLibrary.xcconfig
vendored
Normal file
32
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Base/Targets/StaticLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a static library. Typically, you want to use a platform-specific variant
|
||||
// instead.
|
||||
//
|
||||
|
||||
// Whether to strip out code that isn't called from anywhere
|
||||
DEAD_CODE_STRIPPING = NO
|
||||
|
||||
// Whether to strip debugging symbols when copying resources (like included
|
||||
// binaries).
|
||||
//
|
||||
// Overrides Release.xcconfig when used at the target level.
|
||||
COPY_PHASE_STRIP = NO
|
||||
|
||||
// Whether function calls should be position-dependent (should always be
|
||||
// disabled for library code)
|
||||
GCC_DYNAMIC_NO_PIC = NO
|
||||
|
||||
// Copy headers to "include/LibraryName" in the build folder by default. This
|
||||
// lets consumers use #import <LibraryName/LibraryName.h> syntax even for static
|
||||
// libraries
|
||||
PUBLIC_HEADERS_FOLDER_PATH = include/$PRODUCT_NAME
|
||||
|
||||
// Don't include in an xcarchive
|
||||
SKIP_INSTALL = YES
|
||||
|
||||
// Disallows use of APIs that are not available
|
||||
// to app extensions and linking to frameworks
|
||||
// that have not been built with this setting enabled.
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Application.xcconfig
vendored
Normal file
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Application.xcconfig
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for an application on Mac OS X. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base application settings
|
||||
#include "../Base/Targets/Application.xcconfig"
|
||||
|
||||
// Apply common settings specific to Mac OS X
|
||||
#include "Mac-Base.xcconfig"
|
||||
|
||||
// Whether function calls should be position-dependent (should always be
|
||||
// disabled for library code)
|
||||
GCC_DYNAMIC_NO_PIC = YES
|
19
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Base.xcconfig
vendored
Normal file
19
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Base.xcconfig
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for Mac OS X. This file is not standalone -- it is meant to be included into
|
||||
// a configuration file for a specific type of target.
|
||||
//
|
||||
|
||||
// Whether to combine multiple image resolutions into a multirepresentational
|
||||
// TIFF
|
||||
COMBINE_HIDPI_IMAGES = YES
|
||||
|
||||
// Where to find embedded frameworks
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks
|
||||
|
||||
// The base SDK to use (if no version is specified, the latest version is
|
||||
// assumed)
|
||||
SDKROOT = macosx
|
||||
|
||||
// Supported build architectures
|
||||
VALID_ARCHS = x86_64
|
18
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-DynamicLibrary.xcconfig
vendored
Normal file
18
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-DynamicLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a dynamic library on Mac OS X. This should be set at the target level
|
||||
// for each project configuration.
|
||||
//
|
||||
|
||||
// Import common settings specific to Mac OS X
|
||||
#include "Mac-Base.xcconfig"
|
||||
|
||||
// Whether to strip out code that isn't called from anywhere
|
||||
DEAD_CODE_STRIPPING = NO
|
||||
|
||||
// Whether function calls should be position-dependent (should always be
|
||||
// disabled for library code)
|
||||
GCC_DYNAMIC_NO_PIC = NO
|
||||
|
||||
// Don't include in an xcarchive
|
||||
SKIP_INSTALL = YES
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Framework.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-Framework.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a framework on OS X. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base framework settings
|
||||
#include "../Base/Targets/Framework.xcconfig"
|
||||
|
||||
// Import common settings specific to Mac OS X
|
||||
#include "Mac-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-StaticLibrary.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/Mac OS X/Mac-StaticLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a static library on Mac OS X. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base static library settings
|
||||
#include "../Base/Targets/StaticLibrary.xcconfig"
|
||||
|
||||
// Apply common settings specific to Mac OS X
|
||||
#include "Mac-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Application.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Application.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for an application on iOS. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base application settings
|
||||
#include "../Base/Targets/Application.xcconfig"
|
||||
|
||||
// Apply common settings specific to iOS
|
||||
#include "iOS-Base.xcconfig"
|
18
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Base.xcconfig
vendored
Normal file
18
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Base.xcconfig
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for iOS. This file is not standalone -- it is meant to be included into
|
||||
// a configuration file for a specific type of target.
|
||||
//
|
||||
|
||||
// Xcode needs this to find archived headers if SKIP_INSTALL is set
|
||||
HEADER_SEARCH_PATHS = $(OBJROOT)/UninstalledProducts/include
|
||||
|
||||
// Where to find embedded frameworks
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
|
||||
|
||||
// The base SDK to use (if no version is specified, the latest version is
|
||||
// assumed)
|
||||
SDKROOT = iphoneos
|
||||
|
||||
// Supported device families (1 is iPhone, 2 is iPad)
|
||||
TARGETED_DEVICE_FAMILY = 1,2
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Framework.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-Framework.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a framework on iOS. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base framework settings
|
||||
#include "../Base/Targets/Framework.xcconfig"
|
||||
|
||||
// Import common settings specific to iOS
|
||||
#include "iOS-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-StaticLibrary.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/iOS/iOS-StaticLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a static library on iOS. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base static library settings
|
||||
#include "../Base/Targets/StaticLibrary.xcconfig"
|
||||
|
||||
// Apply common settings specific to iOS
|
||||
#include "iOS-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Application.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Application.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for an application on watchOS. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base application settings
|
||||
#include "../Base/Targets/Application.xcconfig"
|
||||
|
||||
// Apply common settings specific to watchOS
|
||||
#include "tvOS-Base.xcconfig"
|
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Base.xcconfig
vendored
Normal file
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Base.xcconfig
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for watchOS. This file is not standalone -- it is meant to be included into
|
||||
// a configuration file for a specific type of target.
|
||||
//
|
||||
|
||||
// Where to find embedded frameworks
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
|
||||
|
||||
// The base SDK to use (if no version is specified, the latest version is
|
||||
// assumed)
|
||||
SDKROOT = appletvos
|
||||
|
||||
// Supported device families
|
||||
TARGETED_DEVICE_FAMILY = 3
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Framework.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-Framework.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a framework on watchOS. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base framework settings
|
||||
#include "../Base/Targets/Framework.xcconfig"
|
||||
|
||||
// Import common settings specific to iOS
|
||||
#include "tvOS-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-StaticLibrary.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/tvOS/tvOS-StaticLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a static library on watchOS. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base static library settings
|
||||
#include "../Base/Targets/StaticLibrary.xcconfig"
|
||||
|
||||
// Apply common settings specific to watchOS
|
||||
#include "tvOS-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Application.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Application.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for an application on watchOS. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base application settings
|
||||
#include "../Base/Targets/Application.xcconfig"
|
||||
|
||||
// Apply common settings specific to watchOS
|
||||
#include "watchOS-Base.xcconfig"
|
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Base.xcconfig
vendored
Normal file
15
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Base.xcconfig
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for watchOS. This file is not standalone -- it is meant to be included into
|
||||
// a configuration file for a specific type of target.
|
||||
//
|
||||
|
||||
// Where to find embedded frameworks
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
|
||||
|
||||
// The base SDK to use (if no version is specified, the latest version is
|
||||
// assumed)
|
||||
SDKROOT = watchos
|
||||
|
||||
// Supported device families
|
||||
TARGETED_DEVICE_FAMILY = 4
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Framework.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-Framework.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a framework on watchOS. This should be set at the target level for each
|
||||
// project configuration.
|
||||
//
|
||||
|
||||
// Import base framework settings
|
||||
#include "../Base/Targets/Framework.xcconfig"
|
||||
|
||||
// Import common settings specific to iOS
|
||||
#include "watchOS-Base.xcconfig"
|
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-StaticLibrary.xcconfig
vendored
Normal file
11
Carthage/Checkouts/TrueTime.swift/External/xcconfigs/watchOS/watchOS-StaticLibrary.xcconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// This file defines additional configuration options that are appropriate only
|
||||
// for a static library on watchOS. This should be set at the target level for
|
||||
// each project configuration.
|
||||
//
|
||||
|
||||
// Import base static library settings
|
||||
#include "../Base/Targets/StaticLibrary.xcconfig"
|
||||
|
||||
// Apply common settings specific to watchOS
|
||||
#include "watchOS-Base.xcconfig"
|
9
Carthage/Checkouts/TrueTime.swift/Scripts/test
vendored
Executable file
9
Carthage/Checkouts/TrueTime.swift/Scripts/test
vendored
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o nounset -o errexit -o pipefail
|
||||
BUILD_LOG="xcodebuild.log"
|
||||
|
||||
xcodebuild clean test -sdk "$SDK" -scheme "$SCHEME" -destination "$DESTINATION" | tee "$BUILD_LOG" | xcpretty
|
||||
STATUS="${PIPESTATUS[0]}"
|
||||
if [ -f "$BUILD_LOG" ]; then curl -sT "$BUILD_LOG" chunk.io; fi
|
||||
|
||||
exit "$STATUS"
|
4
Carthage/Checkouts/TrueTime.swift/Sources/CTrueTime/module.modulemap
vendored
Normal file
4
Carthage/Checkouts/TrueTime.swift/Sources/CTrueTime/module.modulemap
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
module CTrueTime [system] {
|
||||
header "ntp_types.h"
|
||||
export *
|
||||
}
|
45
Carthage/Checkouts/TrueTime.swift/Sources/CTrueTime/ntp_types.h
vendored
Normal file
45
Carthage/Checkouts/TrueTime.swift/Sources/CTrueTime/ntp_types.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// ntp_types.h
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/11/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef NTP_TYPES_H
|
||||
#define NTP_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t whole;
|
||||
uint16_t fraction;
|
||||
} __attribute__((packed, aligned(1))) ntp_time32_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t whole;
|
||||
uint32_t fraction;
|
||||
} __attribute__((packed, aligned(1))) ntp_time64_t;
|
||||
|
||||
typedef ntp_time64_t ntp_time_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t client_mode: 3;
|
||||
uint8_t version_number: 3;
|
||||
uint8_t leap_indicator: 2;
|
||||
|
||||
uint8_t stratum;
|
||||
uint8_t poll;
|
||||
uint8_t precision;
|
||||
|
||||
ntp_time32_t root_delay;
|
||||
ntp_time32_t root_dispersion;
|
||||
uint8_t reference_id[4];
|
||||
|
||||
ntp_time_t reference_time;
|
||||
ntp_time_t originate_time;
|
||||
ntp_time_t receive_time;
|
||||
ntp_time_t transmit_time;
|
||||
} __attribute__((packed, aligned(1))) ntp_packet_t;
|
||||
|
||||
#endif /* NTP_TYPES_H */
|
89
Carthage/Checkouts/TrueTime.swift/Sources/Endian.swift
vendored
Normal file
89
Carthage/Checkouts/TrueTime.swift/Sources/Endian.swift
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
//
|
||||
// Endian.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/11/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol NetworkOrderConvertible {
|
||||
var byteSwapped: Self { get }
|
||||
}
|
||||
|
||||
extension NetworkOrderConvertible {
|
||||
var bigEndian: Self {
|
||||
return isLittleEndian ? byteSwapped : self
|
||||
}
|
||||
|
||||
var littleEndian: Self {
|
||||
return isLittleEndian ? self : byteSwapped
|
||||
}
|
||||
|
||||
/// Returns the native representation converted from big-endian, changing
|
||||
/// the byte order if necessary.
|
||||
var nativeEndian: Self {
|
||||
return isLittleEndian ? byteSwapped : self
|
||||
}
|
||||
}
|
||||
|
||||
extension Int: NetworkOrderConvertible {}
|
||||
extension ntp_time32_t: NetworkOrderConvertible {
|
||||
var byteSwapped: ntp_time32_t {
|
||||
return ntp_time32_t(whole: whole.byteSwapped, fraction: fraction.byteSwapped)
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_time64_t: NetworkOrderConvertible {
|
||||
var byteSwapped: ntp_time64_t {
|
||||
return ntp_time64_t(whole: whole.byteSwapped, fraction: fraction.byteSwapped)
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_packet_t: NetworkOrderConvertible {
|
||||
var byteSwapped: ntp_packet_t {
|
||||
return ntp_packet_t(client_mode: client_mode,
|
||||
version_number: version_number,
|
||||
leap_indicator: leap_indicator,
|
||||
stratum: stratum,
|
||||
poll: poll,
|
||||
precision: precision,
|
||||
root_delay: root_delay.byteSwapped,
|
||||
root_dispersion: root_dispersion.byteSwapped,
|
||||
reference_id: reference_id,
|
||||
reference_time: reference_time.byteSwapped,
|
||||
originate_time: originate_time.byteSwapped,
|
||||
receive_time: receive_time.byteSwapped,
|
||||
transmit_time: transmit_time.byteSwapped)
|
||||
}
|
||||
}
|
||||
|
||||
extension sockaddr_in6: NetworkOrderConvertible {
|
||||
var byteSwapped: sockaddr_in6 {
|
||||
return sockaddr_in6(sin6_len: sin6_len,
|
||||
sin6_family: sin6_family,
|
||||
sin6_port: sin6_port.byteSwapped,
|
||||
sin6_flowinfo: sin6_flowinfo.byteSwapped,
|
||||
sin6_addr: sin6_addr,
|
||||
sin6_scope_id: sin6_scope_id.byteSwapped)
|
||||
}
|
||||
}
|
||||
|
||||
extension sockaddr_in: NetworkOrderConvertible {
|
||||
var byteSwapped: sockaddr_in {
|
||||
return sockaddr_in(sin_len: sin_len,
|
||||
sin_family: sin_family,
|
||||
sin_port: sin_port.byteSwapped,
|
||||
sin_addr: in_addr(s_addr: sin_addr.s_addr.byteSwapped),
|
||||
sin_zero: sin_zero)
|
||||
}
|
||||
}
|
||||
|
||||
private enum ByteOrder {
|
||||
static let BigEndian = CFByteOrder(CFByteOrderBigEndian.rawValue)
|
||||
static let LittleEndian = CFByteOrder(CFByteOrderLittleEndian.rawValue)
|
||||
static let Unknown = CFByteOrder(CFByteOrderUnknown.rawValue)
|
||||
}
|
||||
|
||||
private let isLittleEndian = CFByteOrderGetCurrent() == ByteOrder.LittleEndian
|
31
Carthage/Checkouts/TrueTime.swift/Sources/GCDLock.swift
vendored
Normal file
31
Carthage/Checkouts/TrueTime.swift/Sources/GCDLock.swift
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// GCDLock.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 10/27/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class GCDLock<Value> {
|
||||
var value: Value
|
||||
let queue = DispatchQueue(label: "")
|
||||
init(value: Value) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
func read() -> Value {
|
||||
var value: Value?
|
||||
queue.sync {
|
||||
value = self.value
|
||||
}
|
||||
return value!
|
||||
}
|
||||
|
||||
func write(_ newValue: Value) {
|
||||
queue.async {
|
||||
self.value = newValue
|
||||
}
|
||||
}
|
||||
}
|
193
Carthage/Checkouts/TrueTime.swift/Sources/HostResolver.swift
vendored
Normal file
193
Carthage/Checkouts/TrueTime.swift/Sources/HostResolver.swift
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
//
|
||||
// HostResolver.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 8/10/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
typealias HostResult = Result<[SocketAddress], NSError>
|
||||
typealias HostCallback = (HostResolver, HostResult) -> Void
|
||||
|
||||
final class HostResolver {
|
||||
let host: String
|
||||
let port: Int
|
||||
let timeout: TimeInterval
|
||||
let onComplete: HostCallback
|
||||
let callbackQueue: DispatchQueue
|
||||
var logger: LogCallback?
|
||||
|
||||
/// Resolves the given hosts in order, returning the first resolved
|
||||
/// addresses or an error if none succeeded.
|
||||
///
|
||||
/// - parameter pool: Pool to resolve
|
||||
/// - parameter port: Port to use when resolving each pool
|
||||
/// - parameter timeout: duration after which to time out DNS resolution
|
||||
/// - parameter logger: logging callback for each host
|
||||
/// - parameter callbackQueue: queue to fire `onComplete` callback
|
||||
/// - parameter onComplete: invoked upon first successfully resolved host
|
||||
/// or when all hosts fail
|
||||
static func resolve(hosts: [(host: String, port: Int)],
|
||||
timeout: TimeInterval,
|
||||
logger: LogCallback?,
|
||||
callbackQueue: DispatchQueue,
|
||||
onComplete: @escaping HostCallback) {
|
||||
precondition(!hosts.isEmpty, "Must include at least one URL")
|
||||
let host = HostResolver(host: hosts[0].host,
|
||||
port: hosts[0].port,
|
||||
timeout: timeout,
|
||||
logger: logger,
|
||||
callbackQueue: callbackQueue) { host, result in
|
||||
switch result {
|
||||
case .success,
|
||||
.failure where hosts.count == 1: onComplete(host, result)
|
||||
case .failure:
|
||||
resolve(hosts: Array(hosts.dropFirst()),
|
||||
timeout: timeout,
|
||||
logger: logger,
|
||||
callbackQueue: callbackQueue,
|
||||
onComplete: onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
host.resolve()
|
||||
}
|
||||
|
||||
required init(host: String,
|
||||
port: Int,
|
||||
timeout: TimeInterval,
|
||||
logger: LogCallback?,
|
||||
callbackQueue: DispatchQueue,
|
||||
onComplete: @escaping HostCallback) {
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.timeout = timeout
|
||||
self.logger = logger
|
||||
self.onComplete = onComplete
|
||||
self.callbackQueue = callbackQueue
|
||||
}
|
||||
|
||||
deinit {
|
||||
assert(!self.started, "Unclosed host")
|
||||
}
|
||||
|
||||
func resolve() {
|
||||
lockQueue.async {
|
||||
guard self.networkHost == nil else { return }
|
||||
self.resolved = false
|
||||
self.networkHost = CFHostCreateWithName(nil, self.host as CFString).takeRetainedValue()
|
||||
var ctx = CFHostClientContext(
|
||||
version: 0,
|
||||
info: UnsafeMutableRawPointer(Unmanaged.passRetained(self).toOpaque()),
|
||||
retain: nil,
|
||||
release: nil,
|
||||
copyDescription: nil
|
||||
)
|
||||
self.callbackPending = true
|
||||
|
||||
if let networkHost = self.networkHost {
|
||||
CFHostSetClient(networkHost, self.hostCallback, &ctx)
|
||||
CFHostScheduleWithRunLoop(networkHost,
|
||||
CFRunLoopGetMain(),
|
||||
CFRunLoopMode.commonModes.rawValue)
|
||||
|
||||
var err: CFStreamError = CFStreamError()
|
||||
if !CFHostStartInfoResolution(networkHost, .addresses, &err) {
|
||||
self.complete(.failure(NSError(trueTimeError: .cannotFindHost)))
|
||||
} else {
|
||||
self.startTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stop(waitUntilFinished wait: Bool = false) {
|
||||
let work = {
|
||||
self.cancelTimer()
|
||||
if let networkHost = self.networkHost {
|
||||
CFHostCancelInfoResolution(networkHost, .addresses)
|
||||
CFHostSetClient(networkHost, nil, nil)
|
||||
CFHostUnscheduleFromRunLoop(networkHost, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
|
||||
self.networkHost = nil
|
||||
}
|
||||
if self.callbackPending {
|
||||
Unmanaged.passUnretained(self).release()
|
||||
self.callbackPending = false
|
||||
}
|
||||
}
|
||||
|
||||
if wait {
|
||||
lockQueue.sync(execute: work)
|
||||
} else {
|
||||
lockQueue.async(execute: work)
|
||||
}
|
||||
}
|
||||
|
||||
func debugLog(_ message: @autoclosure () -> String) {
|
||||
#if DEBUG_LOGGING
|
||||
logger?(message())
|
||||
#endif
|
||||
}
|
||||
|
||||
var timer: DispatchSourceTimer?
|
||||
fileprivate let lockQueue = DispatchQueue(label: "com.instacart.dns.host")
|
||||
fileprivate var networkHost: CFHost?
|
||||
fileprivate var resolved: Bool = false
|
||||
fileprivate var callbackPending: Bool = false
|
||||
private let hostCallback: CFHostClientCallBack = { host, infoType, error, info in
|
||||
guard let info = info else { return }
|
||||
let retainedClient = Unmanaged<HostResolver>.fromOpaque(info)
|
||||
let client = retainedClient.takeUnretainedValue()
|
||||
client.callbackPending = false
|
||||
client.connect(host)
|
||||
retainedClient.release()
|
||||
}
|
||||
}
|
||||
|
||||
extension HostResolver: TimedOperation {
|
||||
var timerQueue: DispatchQueue { return lockQueue }
|
||||
var started: Bool { return self.networkHost != nil }
|
||||
|
||||
func timeoutError(_ error: NSError) {
|
||||
complete(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
private extension HostResolver {
|
||||
func complete(_ result: HostResult) {
|
||||
stop()
|
||||
callbackQueue.async {
|
||||
self.onComplete(self, result)
|
||||
}
|
||||
}
|
||||
|
||||
func connect(_ host: CFHost) {
|
||||
debugLog("Got CFHostStartInfoResolution callback")
|
||||
lockQueue.async {
|
||||
guard self.started && !self.resolved else {
|
||||
self.debugLog("Closed")
|
||||
return
|
||||
}
|
||||
|
||||
var resolved: DarwinBoolean = false
|
||||
let addressData = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as [AnyObject]?
|
||||
guard let addresses = addressData as? [Data], resolved.boolValue else {
|
||||
self.complete(.failure(NSError(trueTimeError: .dnsLookupFailed)))
|
||||
return
|
||||
}
|
||||
|
||||
let socketAddresses = addresses.map { data -> SocketAddress? in
|
||||
let storage = (data as NSData).bytes.bindMemory(to: sockaddr_storage.self, capacity: data.count)
|
||||
return SocketAddress(storage: storage, port: UInt16(self.port))
|
||||
}.compactMap { $0 }
|
||||
|
||||
self.resolved = true
|
||||
self.debugLog("Resolved hosts: \(socketAddresses)")
|
||||
self.complete(.success(socketAddresses))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let defaultNTPPort: Int = 123
|
28
Carthage/Checkouts/TrueTime.swift/Sources/Info.plist
vendored
Normal file
28
Carthage/Checkouts/TrueTime.swift/Sources/Info.plist
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Instacart. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
263
Carthage/Checkouts/TrueTime.swift/Sources/NTPClient.swift
vendored
Normal file
263
Carthage/Checkouts/TrueTime.swift/Sources/NTPClient.swift
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
//
|
||||
// NTPClient.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 10/12/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
struct NTPConfig {
|
||||
let timeout: TimeInterval
|
||||
let maxRetries: Int
|
||||
let maxConnections: Int
|
||||
let maxServers: Int
|
||||
let numberOfSamples: Int
|
||||
let pollInterval: TimeInterval
|
||||
}
|
||||
|
||||
final class NTPClient {
|
||||
let config: NTPConfig
|
||||
init(config: NTPConfig) {
|
||||
self.config = config
|
||||
}
|
||||
|
||||
func start(pool: [String], port: Int) {
|
||||
precondition(!pool.isEmpty, "Must include at least one pool URL")
|
||||
queue.async {
|
||||
precondition(self.reachability.callback == nil, "Already started")
|
||||
self.pool = pool
|
||||
self.port = port
|
||||
self.reachability.callbackQueue = self.queue
|
||||
self.reachability.callback = self.updateReachability
|
||||
self.reachability.startMonitoring()
|
||||
self.startTimer()
|
||||
}
|
||||
}
|
||||
|
||||
func pause() {
|
||||
queue.async {
|
||||
self.cancelTimer()
|
||||
self.reachability.stopMonitoring()
|
||||
self.reachability.callback = nil
|
||||
self.stopQueue()
|
||||
}
|
||||
}
|
||||
|
||||
func fetchIfNeeded(queue callbackQueue: DispatchQueue,
|
||||
first: ReferenceTimeCallback?,
|
||||
completion: ReferenceTimeCallback?) {
|
||||
queue.async {
|
||||
precondition(self.reachability.callback != nil,
|
||||
"Must start client before retrieving time")
|
||||
if let time = self.referenceTime {
|
||||
callbackQueue.async { first?(.success(time)) }
|
||||
} else if let first = first {
|
||||
self.startCallbacks.append((callbackQueue, first))
|
||||
}
|
||||
|
||||
if let time = self.referenceTime, self.finished {
|
||||
callbackQueue.async { completion?(.success(time)) }
|
||||
} else {
|
||||
if let completion = completion {
|
||||
self.completionCallbacks.append((callbackQueue, completion))
|
||||
}
|
||||
self.updateReachability(status: self.reachability.status ?? .notReachable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let referenceTimeLock: GCDLock<ReferenceTime?> = GCDLock(value: nil)
|
||||
var referenceTime: ReferenceTime? {
|
||||
get { return referenceTimeLock.read() }
|
||||
set { referenceTimeLock.write(newValue) }
|
||||
}
|
||||
|
||||
fileprivate func debugLog(_ message: @autoclosure () -> String) {
|
||||
#if DEBUG_LOGGING
|
||||
logger?(message())
|
||||
#endif
|
||||
}
|
||||
|
||||
var logger: LogCallback? = defaultLogger
|
||||
private let queue = DispatchQueue(label: "com.instacart.ntp.client")
|
||||
private let reachability = Reachability()
|
||||
private var completionCallbacks: [(DispatchQueue, ReferenceTimeCallback)] = []
|
||||
private var connections: [NTPConnection] = []
|
||||
private var finished: Bool = false
|
||||
private var invalidated: Bool = false
|
||||
private var startCallbacks: [(DispatchQueue, ReferenceTimeCallback)] = []
|
||||
private var startTime: TimeInterval?
|
||||
private var timer: DispatchSourceTimer?
|
||||
private var port: Int = 123
|
||||
private var pool: [String] = [] {
|
||||
didSet { invalidate() }
|
||||
}
|
||||
}
|
||||
|
||||
private extension NTPClient {
|
||||
var started: Bool { return startTime != nil }
|
||||
func updateReachability(status: ReachabilityStatus) {
|
||||
switch status {
|
||||
case .notReachable:
|
||||
debugLog("Network unreachable")
|
||||
cancelTimer()
|
||||
finish(.failure(NSError(trueTimeError: .offline)))
|
||||
case .reachableViaWWAN, .reachableViaWiFi:
|
||||
debugLog("Network reachable")
|
||||
startTimer()
|
||||
startPool(pool: pool, port: port)
|
||||
}
|
||||
}
|
||||
|
||||
func startTimer() {
|
||||
cancelTimer()
|
||||
if let referenceTime = referenceTime {
|
||||
let remainingInterval = max(0, config.pollInterval - referenceTime.underlyingValue.uptimeInterval)
|
||||
timer = DispatchSource.makeTimerSource(flags: [], queue: queue)
|
||||
timer?.setEventHandler(handler: invalidate)
|
||||
timer?.schedule(deadline: .now() + remainingInterval)
|
||||
timer?.resume()
|
||||
}
|
||||
}
|
||||
|
||||
func cancelTimer() {
|
||||
timer?.cancel()
|
||||
timer = nil
|
||||
}
|
||||
|
||||
func startPool(pool: [String], port: Int) {
|
||||
guard !started && !finished else {
|
||||
debugLog("Already \(started ? "started" : "finished")")
|
||||
return
|
||||
}
|
||||
|
||||
startTime = CFAbsoluteTimeGetCurrent()
|
||||
debugLog("Resolving pool: \(pool)")
|
||||
HostResolver.resolve(hosts: pool.map { ($0, port) },
|
||||
timeout: config.timeout,
|
||||
logger: logger,
|
||||
callbackQueue: queue) { resolver, result in
|
||||
guard self.started && !self.finished else {
|
||||
self.debugLog("Got DNS response after queue stopped: \(resolver), \(result)")
|
||||
return
|
||||
}
|
||||
guard pool == self.pool, port == self.port else {
|
||||
self.debugLog("Got DNS response after pool URLs changed: \(resolver), \(result)")
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case let .success(addresses): self.query(addresses: addresses, host: resolver.host)
|
||||
case let .failure(error): self.finish(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stopQueue() {
|
||||
debugLog("Stopping queue")
|
||||
startTime = nil
|
||||
connections.forEach { $0.close(waitUntilFinished: true) }
|
||||
connections = []
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
stopQueue()
|
||||
finished = false
|
||||
if let referenceTime = referenceTime,
|
||||
reachability.status != .notReachable && !pool.isEmpty {
|
||||
debugLog("Invalidated time \(referenceTime.debugDescription)")
|
||||
startPool(pool: pool, port: port)
|
||||
}
|
||||
}
|
||||
|
||||
func query(addresses: [SocketAddress], host: String) {
|
||||
var results: [String: [FrozenNetworkTimeResult]] = [:]
|
||||
connections = NTPConnection.query(addresses: addresses,
|
||||
config: config,
|
||||
logger: logger,
|
||||
callbackQueue: queue) { connection, result in
|
||||
guard self.started && !self.finished else {
|
||||
self.debugLog("Got NTP response after queue stopped: \(result)")
|
||||
return
|
||||
}
|
||||
|
||||
let host = connection.address.host
|
||||
results[host] = (results[host] ?? []) + [result]
|
||||
|
||||
let responses = Array(results.values)
|
||||
let sampleSize = responses.map { $0.count }.reduce(0, +)
|
||||
let expectedCount = addresses.count * self.config.numberOfSamples
|
||||
let atEnd = sampleSize == expectedCount
|
||||
let times = responses.map { results in
|
||||
results.compactMap { try? $0.get() }
|
||||
}
|
||||
|
||||
self.debugLog("Got \(sampleSize) out of \(expectedCount)")
|
||||
if let time = bestTime(fromResponses: times) {
|
||||
let time = FrozenNetworkTime(networkTime: time, sampleSize: sampleSize, host: host)
|
||||
self.debugLog("\(atEnd ? "Final" : "Best") time: \(time), " +
|
||||
"δ: \(time.serverResponse.delay), " +
|
||||
"θ: \(time.serverResponse.offset)")
|
||||
|
||||
let referenceTime = self.referenceTime ?? ReferenceTime(time)
|
||||
if self.referenceTime == nil {
|
||||
self.referenceTime = referenceTime
|
||||
} else {
|
||||
referenceTime.underlyingValue = time
|
||||
}
|
||||
|
||||
if atEnd {
|
||||
self.finish(.success(referenceTime))
|
||||
} else {
|
||||
self.updateProgress(.success(referenceTime))
|
||||
}
|
||||
} else if atEnd {
|
||||
let error: NSError
|
||||
if case let .failure(failure) = result {
|
||||
error = failure as NSError
|
||||
} else {
|
||||
error = NSError(trueTimeError: .noValidPacket)
|
||||
}
|
||||
|
||||
self.finish(ReferenceTimeResult.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateProgress(_ result: ReferenceTimeResult) {
|
||||
let endTime = CFAbsoluteTimeGetCurrent()
|
||||
let hasStartCallbacks = !startCallbacks.isEmpty
|
||||
startCallbacks.forEach { queue, callback in
|
||||
queue.async {
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
startCallbacks = []
|
||||
if hasStartCallbacks {
|
||||
logDuration(endTime, to: "get first result")
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(Notification(name: .TrueTimeUpdated, object: self, userInfo: nil))
|
||||
}
|
||||
|
||||
func finish(_ result: ReferenceTimeResult) {
|
||||
let endTime = CFAbsoluteTimeGetCurrent()
|
||||
updateProgress(result)
|
||||
completionCallbacks.forEach { queue, callback in
|
||||
queue.async {
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
completionCallbacks = []
|
||||
logDuration(endTime, to: "get last result")
|
||||
finished = (try? result.get()) != nil
|
||||
stopQueue()
|
||||
startTimer()
|
||||
}
|
||||
|
||||
func logDuration(_ endTime: CFAbsoluteTime, to description: String) {
|
||||
if let startTime = startTime {
|
||||
debugLog("Took \(endTime - startTime)s to \(description)")
|
||||
}
|
||||
}
|
||||
}
|
264
Carthage/Checkouts/TrueTime.swift/Sources/NTPConnection.swift
vendored
Normal file
264
Carthage/Checkouts/TrueTime.swift/Sources/NTPConnection.swift
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
//
|
||||
// NTPConnection.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 8/10/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
typealias NTPConnectionCallback = (NTPConnection, FrozenNetworkTimeResult) -> Void
|
||||
|
||||
final class NTPConnection {
|
||||
let address: SocketAddress
|
||||
let timeout: TimeInterval
|
||||
let maxRetries: Int
|
||||
var logger: LogCallback?
|
||||
|
||||
static func query(addresses: [SocketAddress],
|
||||
config: NTPConfig,
|
||||
logger: LogCallback?,
|
||||
callbackQueue: DispatchQueue,
|
||||
progress: @escaping NTPConnectionCallback) -> [NTPConnection] {
|
||||
let connections = addresses.flatMap { address in
|
||||
(0..<config.numberOfSamples).map { _ in
|
||||
NTPConnection(address: address,
|
||||
timeout: config.timeout,
|
||||
maxRetries: config.maxRetries,
|
||||
logger: logger)
|
||||
}
|
||||
}
|
||||
|
||||
var throttleConnections: (() -> Void)?
|
||||
let onComplete: NTPConnectionCallback = { connection, result in
|
||||
progress(connection, result)
|
||||
throttleConnections?()
|
||||
}
|
||||
|
||||
throttleConnections = {
|
||||
let remainingConnections = connections.filter { $0.canRetry }
|
||||
let activeConnections = Array(remainingConnections[0..<min(config.maxConnections,
|
||||
remainingConnections.count)])
|
||||
activeConnections.forEach { $0.start(callbackQueue, onComplete: onComplete) }
|
||||
}
|
||||
throttleConnections?()
|
||||
return connections
|
||||
}
|
||||
|
||||
required init(address: SocketAddress,
|
||||
timeout: TimeInterval,
|
||||
maxRetries: Int,
|
||||
logger: LogCallback?) {
|
||||
self.address = address
|
||||
self.timeout = timeout
|
||||
self.maxRetries = maxRetries
|
||||
self.logger = logger
|
||||
}
|
||||
|
||||
deinit {
|
||||
assert(!self.started, "Unclosed connection")
|
||||
}
|
||||
|
||||
var canRetry: Bool {
|
||||
var canRetry: Bool = false
|
||||
lockQueue.sync {
|
||||
canRetry = self.attempts < self.maxRetries && !self.didTimeout && !self.finished
|
||||
}
|
||||
return canRetry
|
||||
}
|
||||
|
||||
func start(_ callbackQueue: DispatchQueue, onComplete: @escaping NTPConnectionCallback) {
|
||||
lockQueue.async {
|
||||
guard !self.started else { return }
|
||||
var ctx = CFSocketContext(
|
||||
version: 0,
|
||||
info: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
|
||||
retain: nil,
|
||||
release: nil,
|
||||
copyDescription: nil
|
||||
)
|
||||
|
||||
self.attempts += 1
|
||||
self.callbackQueue = callbackQueue
|
||||
self.onComplete = onComplete
|
||||
self.socket = CFSocketCreate(nil,
|
||||
self.address.family,
|
||||
SOCK_DGRAM,
|
||||
IPPROTO_UDP,
|
||||
NTPConnection.callbackFlags,
|
||||
self.dataCallback,
|
||||
&ctx)
|
||||
|
||||
if let socket = self.socket {
|
||||
CFSocketSetSocketFlags(socket, kCFSocketCloseOnInvalidate)
|
||||
self.source = CFSocketCreateRunLoopSource(nil, socket, 0)
|
||||
}
|
||||
|
||||
if let source = self.source {
|
||||
CFRunLoopAddSource(CFRunLoopGetMain(), source, CFRunLoopMode.commonModes)
|
||||
self.startTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func close(waitUntilFinished wait: Bool = false) {
|
||||
let work = {
|
||||
self.cancelTimer()
|
||||
guard let socket = self.socket, let source = self.source else { return }
|
||||
let disabledFlags = NTPConnection.callbackFlags |
|
||||
kCFSocketAutomaticallyReenableDataCallBack |
|
||||
kCFSocketAutomaticallyReenableReadCallBack |
|
||||
kCFSocketAutomaticallyReenableWriteCallBack |
|
||||
kCFSocketAutomaticallyReenableAcceptCallBack
|
||||
CFSocketDisableCallBacks(socket, disabledFlags)
|
||||
CFSocketInvalidate(socket)
|
||||
CFRunLoopRemoveSource(CFRunLoopGetMain(), source, CFRunLoopMode.commonModes)
|
||||
self.socket = nil
|
||||
self.source = nil
|
||||
self.debugLog("Connection closed \(self.address)")
|
||||
}
|
||||
|
||||
if wait {
|
||||
lockQueue.sync(execute: work)
|
||||
} else {
|
||||
lockQueue.async(execute: work)
|
||||
}
|
||||
}
|
||||
|
||||
func debugLog(_ message: @autoclosure () -> String) {
|
||||
#if DEBUG_LOGGING
|
||||
logger?(message())
|
||||
#endif
|
||||
}
|
||||
|
||||
private let dataCallback: CFSocketCallBack = { socket, type, address, data, info in
|
||||
guard let info = info else { return }
|
||||
let client = Unmanaged<NTPConnection>.fromOpaque(info).takeUnretainedValue()
|
||||
guard let socket = socket, CFSocketIsValid(socket) else { return }
|
||||
|
||||
// Can't use switch here as these aren't defined as an enum.
|
||||
if type == .dataCallBack {
|
||||
let data = unsafeBitCast(data, to: CFData.self) as Data
|
||||
client.handleResponse(data)
|
||||
} else if type == .writeCallBack {
|
||||
client.debugLog("Buffer \(client.address) writable - requesting time")
|
||||
client.requestTime()
|
||||
} else {
|
||||
assertionFailure("Unexpected socket callback")
|
||||
}
|
||||
}
|
||||
|
||||
var timer: DispatchSourceTimer?
|
||||
private static let callbackTypes: [CFSocketCallBackType] = [.dataCallBack, .writeCallBack]
|
||||
private static let callbackFlags: CFOptionFlags = callbackTypes.map {
|
||||
$0.rawValue
|
||||
}.reduce(0, |)
|
||||
private let lockQueue = DispatchQueue(label: "com.instacart.ntp.connection")
|
||||
private var attempts: Int = 0
|
||||
private var callbackQueue: DispatchQueue?
|
||||
private var didTimeout: Bool = false
|
||||
private var onComplete: NTPConnectionCallback?
|
||||
private var requestTicks: timeval?
|
||||
private var socket: CFSocket?
|
||||
private var source: CFRunLoopSource?
|
||||
private var startTime: ntp_time_t?
|
||||
private var finished: Bool = false
|
||||
}
|
||||
|
||||
extension NTPConnection: TimedOperation {
|
||||
var timerQueue: DispatchQueue { return lockQueue }
|
||||
var started: Bool { return self.socket != nil }
|
||||
|
||||
func timeoutError(_ error: NSError) {
|
||||
self.didTimeout = true
|
||||
complete(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
private extension NTPConnection {
|
||||
func complete(_ result: FrozenNetworkTimeResult) {
|
||||
guard let callbackQueue = callbackQueue, let onComplete = onComplete else {
|
||||
assertionFailure("Completion callback not initialized")
|
||||
return
|
||||
}
|
||||
|
||||
close()
|
||||
switch result {
|
||||
case let .failure(error) where attempts < maxRetries && !didTimeout:
|
||||
debugLog("Got error from \(address) (attempt \(attempts)), " +
|
||||
"trying again. \(error)")
|
||||
start(callbackQueue, onComplete: onComplete)
|
||||
case .failure, .success:
|
||||
finished = true
|
||||
callbackQueue.async {
|
||||
onComplete(self, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func requestTime() {
|
||||
lockQueue.async {
|
||||
guard let socket = self.socket else {
|
||||
self.debugLog("Socket closed")
|
||||
return
|
||||
}
|
||||
|
||||
self.startTime = ntp_time_t(timeSince1970: .now())
|
||||
self.requestTicks = .uptime()
|
||||
if let startTime = self.startTime {
|
||||
let packet = self.requestPacket(startTime).bigEndian
|
||||
let interval = TimeInterval(milliseconds: startTime.milliseconds)
|
||||
self.debugLog("Sending time: \(Date(timeIntervalSince1970: interval))")
|
||||
let err = CFSocketSendData(socket,
|
||||
self.address.networkData as CFData,
|
||||
packet.data as CFData,
|
||||
self.timeout)
|
||||
if err != .success {
|
||||
self.complete(.failure(NSError(errno: errno)))
|
||||
} else {
|
||||
self.startTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleResponse(_ data: Data) {
|
||||
let responseTicks = timeval.uptime()
|
||||
lockQueue.async {
|
||||
guard self.started else { return } // Socket closed.
|
||||
guard data.count == MemoryLayout<ntp_packet_t>.size else { return } // Invalid packet length.
|
||||
guard let startTime = self.startTime, let requestTicks = self.requestTicks else {
|
||||
assertionFailure("Uninitialized timestamps")
|
||||
return
|
||||
}
|
||||
|
||||
let packet = data.withUnsafeBytes { $0.load(as: ntp_packet_t.self) }.nativeEndian
|
||||
let responseTime = startTime.milliseconds + (responseTicks.milliseconds -
|
||||
requestTicks.milliseconds)
|
||||
|
||||
guard let response = NTPResponse(packet: packet, responseTime: responseTime) else {
|
||||
self.complete(.failure(NSError(trueTimeError: .badServerResponse)))
|
||||
return
|
||||
}
|
||||
|
||||
self.debugLog("Buffer \(self.address) has read data!")
|
||||
self.debugLog("Start time: \(startTime.milliseconds) ms, " +
|
||||
"response: \(packet.timeDescription)")
|
||||
self.debugLog("Clock offset: \(response.offset) milliseconds")
|
||||
self.debugLog("Round-trip delay: \(response.delay) milliseconds")
|
||||
self.complete(.success(FrozenNetworkTime(time: response.networkDate,
|
||||
uptime: responseTicks,
|
||||
serverResponse: response,
|
||||
startTime: startTime)))
|
||||
}
|
||||
}
|
||||
|
||||
func requestPacket(_ time: ntp_time_t) -> ntp_packet_t {
|
||||
var packet = ntp_packet_t()
|
||||
packet.client_mode = 3
|
||||
packet.version_number = 3
|
||||
packet.transmit_time = time
|
||||
return packet
|
||||
}
|
||||
}
|
240
Carthage/Checkouts/TrueTime.swift/Sources/NTPExtensions.swift
vendored
Normal file
240
Carthage/Checkouts/TrueTime.swift/Sources/NTPExtensions.swift
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
//
|
||||
// NTPExtensions.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/10/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension timeval {
|
||||
static func uptime() -> timeval {
|
||||
let now = timeval.now()
|
||||
var boottime = timeval()
|
||||
var mib: [CInt] = [CTL_KERN, KERN_BOOTTIME]
|
||||
var size = MemoryLayout.stride(ofValue: boottime)
|
||||
withFatalErrno { sysctl(&mib, 2, &boottime, &size, nil, 0) }
|
||||
return timeval(tv_sec: now.tv_sec - boottime.tv_sec, tv_usec: now.tv_usec - boottime.tv_usec)
|
||||
}
|
||||
|
||||
var milliseconds: Int64 {
|
||||
return Int64(tv_sec) * Int64(MSEC_PER_SEC) + Int64(tv_usec) / Int64(USEC_PER_MSEC)
|
||||
}
|
||||
}
|
||||
|
||||
extension timeval {
|
||||
static func now() -> timeval {
|
||||
var tv = timeval()
|
||||
withFatalErrno { gettimeofday(&tv, nil) }
|
||||
return tv
|
||||
}
|
||||
}
|
||||
|
||||
// Represents an amount of time since the NTP epoch, January 1, 1900.
|
||||
// https://en.wikipedia.org/wiki/Network_Time_Protocol#Timestamps
|
||||
protocol NTPTimeType {
|
||||
associatedtype ValueType: UnsignedInteger
|
||||
init(whole: ValueType, fraction: ValueType)
|
||||
var whole: ValueType { get }
|
||||
var fraction: ValueType { get }
|
||||
}
|
||||
|
||||
protocol NTPTimevalConvertible: NTPTimeType {}
|
||||
|
||||
extension NTPTimeType {
|
||||
// Interprets the receiver as an elapsed time in milliseconds.
|
||||
var durationInMilliseconds: Int64 {
|
||||
return Int64(whole) * Int64(MSEC_PER_SEC) +
|
||||
fractionInMicroseconds / Int64(USEC_PER_MSEC)
|
||||
}
|
||||
|
||||
var fractionInMicroseconds: Int64 {
|
||||
return Int64(fraction) / Int64(1<<32 / USEC_PER_SEC)
|
||||
}
|
||||
}
|
||||
|
||||
extension NTPTimevalConvertible {
|
||||
init(timeSince1970 time: timeval) {
|
||||
precondition(time.tv_sec >= 0 && time.tv_usec >= 0, "Time must be positive \(time)")
|
||||
self.init(whole: ValueType(UInt64(time.tv_sec) + UInt64(secondsFrom1900To1970)),
|
||||
fraction: ValueType(UInt64(time.tv_usec) * UInt64(1<<32 / USEC_PER_SEC)))
|
||||
}
|
||||
|
||||
var milliseconds: Int64 {
|
||||
return (Int64(whole) - secondsFrom1900To1970) * Int64(MSEC_PER_SEC) +
|
||||
fractionInMicroseconds / Int64(USEC_PER_MSEC)
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_time32_t: NTPTimeType {}
|
||||
extension ntp_time64_t: NTPTimevalConvertible {}
|
||||
|
||||
extension TimeInterval {
|
||||
init(milliseconds: Int64) {
|
||||
self = Double(milliseconds) / Double(MSEC_PER_SEC)
|
||||
}
|
||||
|
||||
init(_ timestamp: timeval) {
|
||||
self = Double(timestamp.tv_sec) + Double(timestamp.tv_usec) / Double(USEC_PER_SEC)
|
||||
}
|
||||
}
|
||||
|
||||
protocol ByteRepresentable {
|
||||
init()
|
||||
}
|
||||
|
||||
extension ByteRepresentable {
|
||||
var data: Data {
|
||||
var buffer = self
|
||||
return Data(bytes: &buffer, count: MemoryLayout.size(ofValue: buffer))
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_packet_t: ByteRepresentable {}
|
||||
extension sockaddr_in: ByteRepresentable {}
|
||||
extension sockaddr_in6: ByteRepresentable {}
|
||||
extension sockaddr_in6: CustomStringConvertible {
|
||||
public var description: String {
|
||||
var buffer = [Int8](repeating: 0, count: Int(INET6_ADDRSTRLEN))
|
||||
var addr = sin6_addr
|
||||
inet_ntop(AF_INET6, &addr, &buffer, socklen_t(INET6_ADDRSTRLEN))
|
||||
|
||||
let host = String(cString: buffer)
|
||||
let port = Int(sin6_port)
|
||||
return "\(host):\(port)"
|
||||
}
|
||||
}
|
||||
|
||||
extension sockaddr_in: CustomStringConvertible {
|
||||
public var description: String {
|
||||
let host = String(cString: inet_ntoa(sin_addr))
|
||||
let port = Int(sin_port)
|
||||
return "\(host):\(port)"
|
||||
}
|
||||
}
|
||||
|
||||
extension HostResolver: CustomStringConvertible {
|
||||
var description: String {
|
||||
return "\(type(of: self))(host: \(host), port: \(port) timeout: \(timeout))"
|
||||
}
|
||||
}
|
||||
|
||||
extension NTPConnection: CustomStringConvertible {
|
||||
var description: String {
|
||||
return "\(type(of: self))(socketAddress: \(address), " +
|
||||
"timeout: \(timeout), " +
|
||||
"maxRetries: \(maxRetries))"
|
||||
}
|
||||
}
|
||||
|
||||
extension FrozenNetworkTime: CustomStringConvertible {
|
||||
var description: String {
|
||||
return "\(type(of: self))(time: \(time), " +
|
||||
"uptime: \(uptime.milliseconds) ms, " +
|
||||
"serverResponse: \(serverResponse), " +
|
||||
"startTime: \(startTime.milliseconds) ms, " +
|
||||
"sampleSize: \((sampleSize ?? 0)), " +
|
||||
"host: \(host ?? "nil"))"
|
||||
}
|
||||
}
|
||||
|
||||
extension NTPResponse: CustomStringConvertible {
|
||||
var description: String {
|
||||
return "\(type(of: self))(packet: \(packet.description), " +
|
||||
"responseTime: \(responseTime) ms, " +
|
||||
"receiveTime: \(receiveTime.milliseconds) ms)"
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_packet_t: CustomStringConvertible {
|
||||
public var description: String {
|
||||
let referenceTime = reference_time.milliseconds
|
||||
let originateTime = originate_time.milliseconds
|
||||
let receiveTime = receive_time.milliseconds
|
||||
let transmitTime = transmit_time.milliseconds
|
||||
return "\(type(of: self))(client_mode: \(client_mode.description), " +
|
||||
"version_number: \(version_number.description), " +
|
||||
"leap_indicator: \(leap_indicator.description), " +
|
||||
"stratum: \(stratum.description), " +
|
||||
"poll: \(poll.description), " +
|
||||
"precision: \(precision.description), " +
|
||||
"root_delay: \(root_delay), " +
|
||||
"root_dispersion: \(root_dispersion), " +
|
||||
"reference_id: \(reference_id), " +
|
||||
"reference_time: \(referenceTime) ms, " +
|
||||
"originate_time: \(originateTime) ms, " +
|
||||
"receive_time: \(receiveTime) ms, " +
|
||||
"transmit_time: \(transmitTime) ms)"
|
||||
}
|
||||
}
|
||||
|
||||
extension ntp_packet_t {
|
||||
var timeDescription: String {
|
||||
return "\(type(of: self))(reference_time: + \(reference_time.milliseconds) ms, " +
|
||||
"originate_time: \(originate_time.milliseconds) ms, " +
|
||||
"receive_time: \(receive_time.milliseconds) ms, " +
|
||||
"transmit_time: \(transmit_time.milliseconds) ms)"
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var localized: String {
|
||||
return Bundle.main.localizedString(forKey: self, value: "", table: "TrueTime")
|
||||
}
|
||||
}
|
||||
|
||||
extension TrueTimeError: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .cannotFindHost: return "The connection failed because the host could not be found.".localized
|
||||
case .dnsLookupFailed: return "The connection failed because the DNS lookup failed.".localized
|
||||
case .timedOut: return "The connection timed out.".localized
|
||||
case .offline: return "The connection failed because the device is not connected to the internet.".localized
|
||||
case .badServerResponse: return "The connection received an invalid server response.".localized
|
||||
case .noValidPacket: return "No valid NTP packet was found.".localized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NSError {
|
||||
convenience init(errno code: Int32) {
|
||||
var userInfo: [String: AnyObject]?
|
||||
if let description = String(validatingUTF8: strerror(code)) {
|
||||
userInfo = [NSLocalizedDescriptionKey: description as AnyObject]
|
||||
}
|
||||
self.init(domain: NSPOSIXErrorDomain, code: Int(code), userInfo: userInfo)
|
||||
}
|
||||
|
||||
convenience init(trueTimeError: TrueTimeError) {
|
||||
self.init(domain: TrueTimeErrorDomain, code: trueTimeError.rawValue, userInfo: [
|
||||
NSLocalizedDescriptionKey: trueTimeError.description
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
func withErrno<X: SignedInteger>(_ block: () -> X) throws -> X {
|
||||
let result = block()
|
||||
if result < 0 {
|
||||
throw NSError(errno: errno)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Equivalent to `withErrno` but asserts at runtime.
|
||||
// Useful when `errno` can only be used to indicate programmer error.
|
||||
@discardableResult
|
||||
func withFatalErrno<X: SignedInteger>(_ block: () -> X) -> X {
|
||||
// swiftlint:disable force_try
|
||||
return try! withErrno(block)
|
||||
// swiftlint:enable force_try
|
||||
}
|
||||
|
||||
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
|
||||
// 70 years plus 17 leap days
|
||||
private let secondsFrom1900To1970: Int64 = ((365 * 70) + 17) * 24 * 60 * 60
|
||||
|
||||
// swiftlint:disable identifier_name
|
||||
let MSEC_PER_SEC: UInt64 = 1000
|
||||
let USEC_PER_MSEC: UInt64 = 1000
|
||||
// swiftlint:enable identifier_name
|
68
Carthage/Checkouts/TrueTime.swift/Sources/NTPResponse.swift
vendored
Normal file
68
Carthage/Checkouts/TrueTime.swift/Sources/NTPResponse.swift
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// NTPResponse.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 10/14/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NTPResponse {
|
||||
let packet: ntp_packet_t
|
||||
let responseTime: Int64
|
||||
let receiveTime: timeval
|
||||
init?(packet: ntp_packet_t, responseTime: Int64, receiveTime: timeval = .now()) {
|
||||
self.packet = packet
|
||||
self.responseTime = responseTime
|
||||
self.receiveTime = receiveTime
|
||||
guard isValidResponse else { return nil }
|
||||
}
|
||||
|
||||
// See https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm
|
||||
var offset: Int64 {
|
||||
let T = offsetValues
|
||||
return ((T[1] - T[0]) + (T[2] - T[3])) / 2
|
||||
}
|
||||
|
||||
var delay: Int64 {
|
||||
let T = offsetValues
|
||||
return (T[3] - T[0]) - (T[2] - T[1])
|
||||
}
|
||||
|
||||
var networkDate: Date {
|
||||
let interval = TimeInterval(milliseconds: responseTime + offset)
|
||||
return Date(timeIntervalSince1970: interval)
|
||||
}
|
||||
}
|
||||
|
||||
func bestTime(fromResponses times: [[FrozenNetworkTime]]) -> FrozenNetworkTime? {
|
||||
let bestTimes = times.map { serverTimes -> FrozenNetworkTime? in
|
||||
serverTimes.min { $0.serverResponse.delay < $1.serverResponse.delay }
|
||||
}.compactMap { $0 }.sorted { $0.serverResponse.offset < $1.serverResponse.offset }
|
||||
|
||||
return bestTimes.isEmpty ? nil : bestTimes[bestTimes.count / 2]
|
||||
}
|
||||
|
||||
private extension NTPResponse {
|
||||
var isValidResponse: Bool {
|
||||
return packet.stratum > 0 && packet.stratum < 16 &&
|
||||
packet.root_delay.durationInMilliseconds < maxRootDispersion &&
|
||||
packet.root_dispersion.durationInMilliseconds < maxRootDispersion &&
|
||||
packet.client_mode == ntpModeServer &&
|
||||
packet.leap_indicator != leapIndicatorUnknown &&
|
||||
abs(receiveTime.milliseconds - packet.originate_time.milliseconds - delay) < maxDelayDelta
|
||||
}
|
||||
|
||||
var offsetValues: [Int64] {
|
||||
return [packet.originate_time.milliseconds,
|
||||
packet.receive_time.milliseconds,
|
||||
packet.transmit_time.milliseconds,
|
||||
responseTime]
|
||||
}
|
||||
}
|
||||
|
||||
private let maxRootDispersion: Int64 = 100
|
||||
private let maxDelayDelta: Int64 = 100
|
||||
private let ntpModeServer: UInt8 = 4
|
||||
private let leapIndicatorUnknown: UInt8 = 3
|
112
Carthage/Checkouts/TrueTime.swift/Sources/Reachability.swift
vendored
Normal file
112
Carthage/Checkouts/TrueTime.swift/Sources/Reachability.swift
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// Reachability.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/21/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SystemConfiguration
|
||||
|
||||
enum ReachabilityStatus {
|
||||
case notReachable
|
||||
case reachableViaWWAN
|
||||
case reachableViaWiFi
|
||||
}
|
||||
|
||||
final class Reachability {
|
||||
var callback: ((ReachabilityStatus) -> Void)?
|
||||
var callbackQueue: DispatchQueue = .main
|
||||
var status: ReachabilityStatus? {
|
||||
if let networkReachability = self.networkReachability {
|
||||
var flags = SCNetworkReachabilityFlags()
|
||||
if SCNetworkReachabilityGetFlags(networkReachability, &flags) {
|
||||
return ReachabilityStatus(flags)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var online: Bool {
|
||||
return status != nil && status != .notReachable
|
||||
}
|
||||
|
||||
deinit {
|
||||
stopMonitoring()
|
||||
}
|
||||
|
||||
func startMonitoring() {
|
||||
var address = sockaddr_in()
|
||||
address.sin_len = UInt8(MemoryLayout.size(ofValue: address))
|
||||
address.sin_family = sa_family_t(AF_INET)
|
||||
networkReachability = withUnsafePointer(to: &address) { pointer in
|
||||
pointer.withMemoryRebound(to: sockaddr.self, capacity: MemoryLayout<sockaddr>.size) {
|
||||
SCNetworkReachabilityCreateWithAddress(nil, $0)
|
||||
}
|
||||
}
|
||||
|
||||
guard let networkReachability = networkReachability else {
|
||||
assertionFailure("SCNetworkReachabilityCreateWithAddress returned NULL")
|
||||
return
|
||||
}
|
||||
|
||||
var context = SCNetworkReachabilityContext(
|
||||
version: 0,
|
||||
info: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
|
||||
retain: nil,
|
||||
release: nil,
|
||||
copyDescription: nil
|
||||
)
|
||||
|
||||
SCNetworkReachabilitySetCallback(networkReachability, Reachability.reachabilityCallback, &context)
|
||||
SCNetworkReachabilitySetDispatchQueue(networkReachability, .global())
|
||||
|
||||
if let status = status {
|
||||
updateStatus(status)
|
||||
}
|
||||
}
|
||||
|
||||
func stopMonitoring() {
|
||||
if let networkReachability = networkReachability {
|
||||
SCNetworkReachabilitySetCallback(networkReachability, nil, nil)
|
||||
SCNetworkReachabilitySetDispatchQueue(networkReachability, nil)
|
||||
self.networkReachability = nil
|
||||
}
|
||||
}
|
||||
|
||||
private var networkReachability: SCNetworkReachability?
|
||||
private static let reachabilityCallback: SCNetworkReachabilityCallBack = { _, flags, info in
|
||||
guard let info = info else { return }
|
||||
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
|
||||
reachability.updateStatus(ReachabilityStatus(flags))
|
||||
}
|
||||
}
|
||||
|
||||
private extension Reachability {
|
||||
func updateStatus(_ status: ReachabilityStatus) {
|
||||
callbackQueue.async {
|
||||
self.callback?(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension ReachabilityStatus {
|
||||
init(_ flags: SCNetworkReachabilityFlags) {
|
||||
let isReachable = flags.contains(.reachable)
|
||||
let needsConnection = flags.contains(.connectionRequired)
|
||||
let connectsAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic)
|
||||
let connectsWithoutInteraction = connectsAutomatically && !flags.contains(.interventionRequired)
|
||||
let isNetworkReachable = isReachable && (!needsConnection || connectsWithoutInteraction)
|
||||
if !isNetworkReachable {
|
||||
self = .notReachable
|
||||
} else {
|
||||
#if os(iOS)
|
||||
if flags.contains(.isWWAN) {
|
||||
self = .reachableViaWWAN
|
||||
return
|
||||
}
|
||||
#endif
|
||||
self = .reachableViaWiFi
|
||||
}
|
||||
}
|
||||
}
|
66
Carthage/Checkouts/TrueTime.swift/Sources/ReferenceTime.swift
vendored
Normal file
66
Carthage/Checkouts/TrueTime.swift/Sources/ReferenceTime.swift
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// FrozenReferenceTime.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 10/26/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
typealias FrozenTimeResult = Result<FrozenTime, NSError>
|
||||
typealias FrozenTimeCallback = (FrozenTimeResult) -> Void
|
||||
|
||||
typealias FrozenNetworkTimeResult = Result<FrozenNetworkTime, NSError>
|
||||
typealias FrozenNetworkTimeCallback = (FrozenNetworkTimeResult) -> Void
|
||||
|
||||
protocol FrozenTime {
|
||||
var time: Date { get }
|
||||
var uptime: timeval { get }
|
||||
}
|
||||
|
||||
struct FrozenReferenceTime: FrozenTime {
|
||||
let time: Date
|
||||
let uptime: timeval
|
||||
}
|
||||
|
||||
struct FrozenNetworkTime: FrozenTime {
|
||||
let time: Date
|
||||
let uptime: timeval
|
||||
let serverResponse: NTPResponse
|
||||
let startTime: ntp_time_t
|
||||
let sampleSize: Int?
|
||||
let host: String?
|
||||
|
||||
init(time: Date,
|
||||
uptime: timeval,
|
||||
serverResponse: NTPResponse,
|
||||
startTime: ntp_time_t,
|
||||
sampleSize: Int? = 0,
|
||||
host: String? = nil) {
|
||||
self.time = time
|
||||
self.uptime = uptime
|
||||
self.serverResponse = serverResponse
|
||||
self.startTime = startTime
|
||||
self.sampleSize = sampleSize
|
||||
self.host = host
|
||||
}
|
||||
|
||||
init(networkTime time: FrozenNetworkTime, sampleSize: Int, host: String) {
|
||||
self.init(time: time.time,
|
||||
uptime: time.uptime,
|
||||
serverResponse: time.serverResponse,
|
||||
startTime: time.startTime,
|
||||
sampleSize: sampleSize,
|
||||
host: host)
|
||||
}
|
||||
}
|
||||
|
||||
extension FrozenTime {
|
||||
var uptimeInterval: TimeInterval {
|
||||
let currentUptime = timeval.uptime()
|
||||
return TimeInterval(milliseconds: currentUptime.milliseconds - uptime.milliseconds)
|
||||
}
|
||||
|
||||
func now() -> Date {
|
||||
return time.addingTimeInterval(uptimeInterval)
|
||||
}
|
||||
}
|
69
Carthage/Checkouts/TrueTime.swift/Sources/SocketAddress.swift
vendored
Normal file
69
Carthage/Checkouts/TrueTime.swift/Sources/SocketAddress.swift
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// SocketAddress.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 9/14/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum SocketAddress {
|
||||
case iPv4(sockaddr_in)
|
||||
case iPv6(sockaddr_in6)
|
||||
|
||||
init?(storage: UnsafePointer<sockaddr_storage>, port: UInt16? = nil) {
|
||||
switch Int32(storage.pointee.ss_family) {
|
||||
case AF_INET:
|
||||
self = storage.withMemoryRebound(to: sockaddr_in.self, capacity: 1) { pointer in
|
||||
var addr = pointer.pointee.nativeEndian
|
||||
addr.sin_port = port ?? addr.sin_port
|
||||
return .iPv4(addr)
|
||||
}
|
||||
case AF_INET6:
|
||||
self = storage.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) { pointer in
|
||||
var addr = pointer.pointee.nativeEndian
|
||||
addr.sin6_port = port ?? addr.sin6_port
|
||||
return .iPv6(addr)
|
||||
}
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var family: Int32 {
|
||||
switch self {
|
||||
case .iPv4: return PF_INET
|
||||
case .iPv6: return PF_INET6
|
||||
}
|
||||
}
|
||||
|
||||
var networkData: Data {
|
||||
switch self {
|
||||
case .iPv4(let address): return address.bigEndian.data as Data
|
||||
case .iPv6(let address): return address.bigEndian.data as Data
|
||||
}
|
||||
}
|
||||
|
||||
var host: String {
|
||||
switch self {
|
||||
case .iPv4(let address): return address.description
|
||||
case .iPv6(let address): return address.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketAddress: CustomStringConvertible {
|
||||
var description: String {
|
||||
return host
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketAddress: Hashable {
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(host.hashValue)
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: SocketAddress, rhs: SocketAddress) -> Bool {
|
||||
return lhs.host == rhs.host
|
||||
}
|
38
Carthage/Checkouts/TrueTime.swift/Sources/TimedOperation.swift
vendored
Normal file
38
Carthage/Checkouts/TrueTime.swift/Sources/TimedOperation.swift
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// TimedOperation.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/18/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol TimedOperation: class {
|
||||
var started: Bool { get }
|
||||
var timeout: TimeInterval { get }
|
||||
var timer: DispatchSourceTimer? { get set }
|
||||
var timerQueue: DispatchQueue { get }
|
||||
|
||||
func debugLog(_ message: @autoclosure () -> String)
|
||||
func timeoutError(_ error: NSError)
|
||||
}
|
||||
|
||||
extension TimedOperation {
|
||||
func startTimer() {
|
||||
cancelTimer()
|
||||
timer = DispatchSource.makeTimerSource(flags: [], queue: timerQueue)
|
||||
timer?.schedule(deadline: .now() + timeout)
|
||||
timer?.setEventHandler {
|
||||
guard self.started else { return }
|
||||
self.debugLog("Got timeout for \(self)")
|
||||
self.timeoutError(NSError(trueTimeError: .timedOut))
|
||||
}
|
||||
timer?.resume()
|
||||
}
|
||||
|
||||
func cancelTimer() {
|
||||
timer?.cancel()
|
||||
timer = nil
|
||||
}
|
||||
}
|
26
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.h
vendored
Normal file
26
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.h
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// TrueTime.h
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/9/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
#import "ntp_types.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
//! Project version number for TrueTime.
|
||||
FOUNDATION_EXPORT double TrueTimeVersionNumber;
|
||||
|
||||
//! Project version string for TrueTime.
|
||||
FOUNDATION_EXPORT const unsigned char TrueTimeVersionNumberString[];
|
||||
|
||||
//! Domain for TrueTime errors.
|
||||
FOUNDATION_EXPORT NSString * const TrueTimeErrorDomain;
|
||||
|
||||
//! Notification sent whenever a TrueTimeClient's reference time is updated.
|
||||
FOUNDATION_EXPORT NSString * const TrueTimeUpdatedNotification;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
12
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.m
vendored
Normal file
12
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.m
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// TrueTime.m
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 8/15/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TrueTime.h"
|
||||
|
||||
NSString * const TrueTimeErrorDomain = @"com.instacart.TrueTimeErrorDomain";
|
||||
NSString * const TrueTimeUpdatedNotification = @"TrueTimeUpdatedNotification";
|
137
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.swift
vendored
Normal file
137
Carthage/Checkouts/TrueTime.swift/Sources/TrueTime.swift
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
//
|
||||
// TrueTime.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/9/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public enum TrueTimeError: Int {
|
||||
case cannotFindHost
|
||||
case dnsLookupFailed
|
||||
case timedOut
|
||||
case offline
|
||||
case badServerResponse
|
||||
case noValidPacket
|
||||
}
|
||||
|
||||
@objc(NTPReferenceTime)
|
||||
public final class ReferenceTime: NSObject {
|
||||
@objc public var uptimeInterval: TimeInterval { return underlyingValue.uptimeInterval }
|
||||
@objc public var time: Date { return underlyingValue.time }
|
||||
@objc public var uptime: timeval { return underlyingValue.uptime }
|
||||
@objc public func now() -> Date { return underlyingValue.now() }
|
||||
|
||||
public convenience init(time: Date, uptime: timeval) {
|
||||
self.init(FrozenReferenceTime(time: time, uptime: uptime))
|
||||
}
|
||||
|
||||
init(_ underlyingValue: FrozenTime) {
|
||||
self.underlyingValueLock = GCDLock(value: underlyingValue)
|
||||
}
|
||||
|
||||
public override var description: String {
|
||||
return "\(type(of: self))(underlyingValue: \(underlyingValue)"
|
||||
}
|
||||
|
||||
private let underlyingValueLock: GCDLock<FrozenTime>
|
||||
var underlyingValue: FrozenTime {
|
||||
get { return underlyingValueLock.read() }
|
||||
set { underlyingValueLock.write(newValue) }
|
||||
}
|
||||
}
|
||||
|
||||
public typealias ReferenceTimeResult = Result<ReferenceTime, NSError>
|
||||
public typealias ReferenceTimeCallback = (ReferenceTimeResult) -> Void
|
||||
public typealias LogCallback = (String) -> Void
|
||||
|
||||
@objc public final class TrueTimeClient: NSObject {
|
||||
@objc public static let sharedInstance = TrueTimeClient()
|
||||
@objc required public init(timeout: TimeInterval = 8,
|
||||
maxRetries: Int = 3,
|
||||
maxConnections: Int = 5,
|
||||
maxServers: Int = 5,
|
||||
numberOfSamples: Int = 4,
|
||||
pollInterval: TimeInterval = 512) {
|
||||
config = NTPConfig(timeout: timeout,
|
||||
maxRetries: maxRetries,
|
||||
maxConnections: maxConnections,
|
||||
maxServers: maxServers,
|
||||
numberOfSamples: numberOfSamples,
|
||||
pollInterval: pollInterval)
|
||||
ntp = NTPClient(config: config)
|
||||
}
|
||||
|
||||
@objc public func start(pool: [String] = ["time.apple.com"], port: Int = 123) {
|
||||
ntp.start(pool: pool, port: port)
|
||||
}
|
||||
|
||||
@objc public func pause() {
|
||||
ntp.pause()
|
||||
}
|
||||
|
||||
public func fetchIfNeeded(queue callbackQueue: DispatchQueue = .main,
|
||||
first: ReferenceTimeCallback? = nil,
|
||||
completion: ReferenceTimeCallback? = nil) {
|
||||
ntp.fetchIfNeeded(queue: callbackQueue, first: first, completion: completion)
|
||||
}
|
||||
|
||||
#if DEBUG_LOGGING
|
||||
@objc public var logCallback: LogCallback? = defaultLogger {
|
||||
didSet {
|
||||
ntp.logger = logCallback
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@objc public var referenceTime: ReferenceTime? { return ntp.referenceTime }
|
||||
@objc public var timeout: TimeInterval { return config.timeout }
|
||||
@objc public var maxRetries: Int { return config.maxRetries }
|
||||
@objc public var maxConnections: Int { return config.maxConnections }
|
||||
@objc public var maxServers: Int { return config.maxServers}
|
||||
@objc public var numberOfSamples: Int { return config.numberOfSamples}
|
||||
|
||||
private let config: NTPConfig
|
||||
private let ntp: NTPClient
|
||||
}
|
||||
|
||||
extension TrueTimeClient {
|
||||
@objc public func fetchFirstIfNeeded(success: @escaping (ReferenceTime) -> Void, failure: ((NSError) -> Void)?) {
|
||||
fetchFirstIfNeeded(success: success, failure: failure, onQueue: .main)
|
||||
}
|
||||
|
||||
@objc public func fetchIfNeeded(success: @escaping (ReferenceTime) -> Void, failure: ((NSError) -> Void)?) {
|
||||
fetchIfNeeded(success: success, failure: failure, onQueue: .main)
|
||||
}
|
||||
|
||||
@objc public func fetchFirstIfNeeded(success: @escaping (ReferenceTime) -> Void,
|
||||
failure: ((NSError) -> Void)?,
|
||||
onQueue queue: DispatchQueue) {
|
||||
fetchIfNeeded(queue: queue, first: { result in
|
||||
self.mapBridgedResult(result, success: success, failure: failure)
|
||||
})
|
||||
}
|
||||
|
||||
@objc public func fetchIfNeeded(success: @escaping (ReferenceTime) -> Void,
|
||||
failure: ((NSError) -> Void)?,
|
||||
onQueue queue: DispatchQueue) {
|
||||
fetchIfNeeded(queue: queue) { result in
|
||||
self.mapBridgedResult(result, success: success, failure: failure)
|
||||
}
|
||||
}
|
||||
|
||||
private func mapBridgedResult(_ result: ReferenceTimeResult,
|
||||
success: (ReferenceTime) -> Void,
|
||||
failure: ((NSError) -> Void)?) {
|
||||
switch result {
|
||||
case let .success(value):
|
||||
success(value)
|
||||
case let .failure(error):
|
||||
failure?(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let defaultLogger: LogCallback = { print($0) }
|
22
Carthage/Checkouts/TrueTime.swift/Tests/ArbitraryExtensions.swift
vendored
Normal file
22
Carthage/Checkouts/TrueTime.swift/Tests/ArbitraryExtensions.swift
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// ArbitraryExtensions.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/19/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import TrueTime
|
||||
import SwiftCheck
|
||||
|
||||
extension timeval: Arbitrary {
|
||||
public static var arbitrary: Gen<timeval> {
|
||||
return Gen<(Int, Int32)>.zip(Int.arbitrary, Int32.arbitrary).map(timeval.init)
|
||||
}
|
||||
}
|
||||
|
||||
extension timeval {
|
||||
static var arbitraryPositive: Gen<timeval> {
|
||||
return arbitrary.suchThat { $0.tv_sec > 0 && $0.tv_usec > 0 }
|
||||
}
|
||||
}
|
24
Carthage/Checkouts/TrueTime.swift/Tests/Info.plist
vendored
Normal file
24
Carthage/Checkouts/TrueTime.swift/Tests/Info.plist
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
23
Carthage/Checkouts/TrueTime.swift/Tests/NTPExtensionsSpec.swift
vendored
Normal file
23
Carthage/Checkouts/TrueTime.swift/Tests/NTPExtensionsSpec.swift
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// NTPExtensionsSpec.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 7/18/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import TrueTime
|
||||
import Nimble
|
||||
import Quick
|
||||
import SwiftCheck
|
||||
|
||||
final class NTPExtensionsSpec: QuickSpec {
|
||||
override func spec() {
|
||||
it("ntp_time64_t") {
|
||||
property("Matches timeval precision") <- forAll(timeval.arbitraryPositive) { time in
|
||||
let ntp = ntp_time64_t(timeSince1970: time)
|
||||
return ntp.milliseconds == time.milliseconds
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
Carthage/Checkouts/TrueTime.swift/Tests/NTPIntegrationSpec.swift
vendored
Normal file
69
Carthage/Checkouts/TrueTime.swift/Tests/NTPIntegrationSpec.swift
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// NTPIntegrationSpec.swift
|
||||
// TrueTime
|
||||
//
|
||||
// Created by Michael Sanders on 8/1/16.
|
||||
// Copyright © 2016 Instacart. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import TrueTime
|
||||
import Nimble
|
||||
import Quick
|
||||
|
||||
final class NTPIntegrationSpec: QuickSpec {
|
||||
override func spec() {
|
||||
describe("fetchIfNeeded") {
|
||||
it("should ignore outliers") {
|
||||
self.testReferenceTimeOutliers()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension NTPIntegrationSpec {
|
||||
func testReferenceTimeOutliers() {
|
||||
let clients = (0..<100).map { _ in TrueTimeClient() }
|
||||
waitUntil(timeout: 60) { done in
|
||||
var results: [ReferenceTimeResult?] = Array(repeating: nil, count: clients.count)
|
||||
let start = NSDate()
|
||||
let finish = {
|
||||
let end = NSDate()
|
||||
let results = results.compactMap { $0 }
|
||||
let times = results.compactMap { try? $0.get() }
|
||||
let errors: [Error] = results.compactMap {
|
||||
guard case let .failure(failure) = $0 else { return nil }
|
||||
|
||||
return failure
|
||||
}
|
||||
expect(times).notTo(beEmpty(), description: "Expected times, got: \(errors)")
|
||||
print("Got \(times.count) times for \(results.count) results")
|
||||
|
||||
let sortedTimes = times.sorted {
|
||||
$0.time.timeIntervalSince1970 < $1.time.timeIntervalSince1970
|
||||
}
|
||||
|
||||
if !sortedTimes.isEmpty {
|
||||
let medianTime = sortedTimes[sortedTimes.count / 2]
|
||||
let maxDelta = end.timeIntervalSince1970 - start.timeIntervalSince1970
|
||||
for time in times {
|
||||
let delta = abs(time.time.timeIntervalSince1970 -
|
||||
medianTime.time.timeIntervalSince1970)
|
||||
expect(delta) <= maxDelta
|
||||
}
|
||||
}
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
for (idx, client) in clients.enumerated() {
|
||||
client.start(pool: ["time.apple.com"])
|
||||
client.fetchIfNeeded { result in
|
||||
results[idx] = result
|
||||
if !results.contains(where: { $0 == nil }) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
Carthage/Checkouts/TrueTime.swift/TrueTime.podspec
vendored
Normal file
19
Carthage/Checkouts/TrueTime.swift/TrueTime.podspec
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'TrueTime'
|
||||
s.version = '5.1.0'
|
||||
s.summary = 'NTP library for Swift. Get the true time impervious to device clock changes.'
|
||||
|
||||
s.homepage = 'https://github.com/instacart/TrueTime.swift'
|
||||
s.license = { :type => 'Apache License, Version 2.0', :file => 'LICENSE' }
|
||||
s.author = { 'Michael Sanders' => 'msanders@instacart.com' }
|
||||
s.source = { :git => 'https://github.com/instacart/TrueTime.swift.git', :tag => s.version }
|
||||
s.swift_version = '5.0'
|
||||
|
||||
s.requires_arc = true
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
|
||||
s.source_files = 'Sources/**/*.{swift,h,m}'
|
||||
s.public_header_files = 'Sources/**/*.h'
|
||||
end
|
7
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
vendored
Normal file
7
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:/Users/yam/Documents/src/instacart/NetworkTime.swift/TrueTime.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
113
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/xcshareddata/xcschemes/TrueTime-Mac.xcscheme
vendored
Normal file
113
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/xcshareddata/xcschemes/TrueTime-Mac.xcscheme
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "287C37A31D4419F800084D47"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-Mac"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "280090491D444B64004C788E"
|
||||
BuildableName = "TrueTime-MacTests.xctest"
|
||||
BlueprintName = "TrueTime-MacTests"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "280090491D444B64004C788E"
|
||||
BuildableName = "TrueTime-MacTests.xctest"
|
||||
BlueprintName = "TrueTime-MacTests"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "287C37A31D4419F800084D47"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-Mac"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "287C37A31D4419F800084D47"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-Mac"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "287C37A31D4419F800084D47"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-Mac"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
113
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/xcshareddata/xcschemes/TrueTime-iOS.xcscheme
vendored
Normal file
113
Carthage/Checkouts/TrueTime.swift/TrueTime.xcodeproj/xcshareddata/xcschemes/TrueTime-iOS.xcscheme
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DC11D314E7B003491D9"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-iOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DCB1D314E7B003491D9"
|
||||
BuildableName = "TrueTimeTests.xctest"
|
||||
BlueprintName = "TrueTime-iOSTests"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DCB1D314E7B003491D9"
|
||||
BuildableName = "TrueTimeTests.xctest"
|
||||
BlueprintName = "TrueTime-iOSTests"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DC11D314E7B003491D9"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-iOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DC11D314E7B003491D9"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-iOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28482DC11D314E7B003491D9"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-iOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "285047DE1D4D641400DE4CE8"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-tvOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "28682B611D4D2F4600D65223"
|
||||
BuildableName = "TrueTime-TVTests.xctest"
|
||||
BlueprintName = "TrueTime-TVTests"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "285047DE1D4D641400DE4CE8"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-tvOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "285047DE1D4D641400DE4CE8"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-tvOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "285047DE1D4D641400DE4CE8"
|
||||
BuildableName = "TrueTime.framework"
|
||||
BlueprintName = "TrueTime-tvOS"
|
||||
ReferencedContainer = "container:TrueTime.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
BIN
Carthage/Checkouts/TrueTime.swift/ntp.gif
vendored
Normal file
BIN
Carthage/Checkouts/TrueTime.swift/ntp.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
Carthage/Checkouts/TrueTime.swift/truetime.png
vendored
Normal file
BIN
Carthage/Checkouts/TrueTime.swift/truetime.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Reference in New Issue
Block a user