Skip to content

Commit

Permalink
Merge branch 'brian/add-windows-support' into bsneed/windows
Browse files Browse the repository at this point in the history
  • Loading branch information
bsneed committed May 15, 2024
2 parents c68e60d + a970757 commit 65b037e
Show file tree
Hide file tree
Showing 23 changed files with 636 additions and 486 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true

[*.swift]
indent_style = space
indent_size = 4
20 changes: 20 additions & 0 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ jobs:
- name: Run tests
run: swift test --enable-test-discovery

# Windows support is still very much a work in progress
# We use a different action here to be able to use a more
# up-to-date toolchain.
build_and_test_spm_windows:
needs: cancel_previous
runs-on: windows-latest
steps:
- uses: compnerd/gha-setup-swift@main
with:
release-tag-name: "20231116.2"
github-repo: "thebrowsercompany/swift-build"
release-asset-name: installer-amd64.exe
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v2
- name: Build
run: swift build
# Testing disabled until https://github.com/segmentio/analytics-swift/issues/279 is fixed
# - name: Run tests
# run: swift test --enable-test-discovery

build_and_test_ios:
needs: cancel_previous
runs-on: macos-14
Expand Down
5 changes: 2 additions & 3 deletions Examples/other_plugins/NotificationTracking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@

// MARK: Common

#if !os(Linux) && !os(macOS)
#if !os(Linux) && !os(macOS) && !os(Windows)

import Foundation
import Segment

class NotificationTracking: Plugin {
var type: PluginType = .utility
weak var analytics: Analytics?

func trackNotification(_ properties: [String: Codable], fromLaunch launch: Bool) {
if launch {
analytics?.track(name: "Push Notification Tapped", properties: properties)
Expand Down Expand Up @@ -95,4 +95,3 @@ extension NotificationTracking: iOSLifecycle {
}

#endif

4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
{
"identity" : "sovran-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/segmentio/Sovran-Swift.git",
"location" : "https://github.com/segmentio/sovran-swift.git",
"state" : {
"revision" : "a342b905f6baa64499cabdf61ccc185ec476b7b2",
"version" : "1.1.1"
}
}
],
"version" : 2
}
}
78 changes: 39 additions & 39 deletions Sources/Segment/Analytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,23 @@ public class Analytics {
}
internal var store: Store
internal var storage: Storage

/// Enabled/disables debug logging to trace your data going through the SDK.
public static var debugLogsEnabled = false

public var timeline: Timeline

static internal let deadInstance = "DEADINSTANCE"
static internal weak var firstInstance: Analytics? = nil

@Atomic static internal var activeWriteKeys = [String]()

/**
This method isn't a traditional singleton implementation. It's provided here
to ease migration from analytics-ios to analytics-swift. Rather than return a
singleton, it returns the first instance of Analytics created, OR an instance
who's writekey is "DEADINSTANCE".

In the case of a dead instance, an assert will be thrown when in DEBUG builds to
assist developers in knowning that `shared()` is being called too soon.
*/
Expand All @@ -45,16 +46,16 @@ public class Analytics {
return a
}
}

#if DEBUG
if isUnitTesting == false {
assert(true == false, "An instance of Analytice does not exist!")
}
#endif

return Analytics(configuration: Configuration(writeKey: deadInstance))
}

/// Initialize this instance of Analytics with a given configuration setup.
/// - Parameters:
/// - configuration: The configuration to use
Expand All @@ -75,40 +76,40 @@ public class Analytics {
operatingMode: configuration.values.operatingMode
)
timeline = Timeline()

// provide our default state
store.provide(state: System.defaultState(configuration: configuration, from: storage))
store.provide(state: UserInfo.defaultState(from: storage, anonIdGenerator: configuration.values.anonymousIdGenerator))

storage.analytics = self

checkSharedInstance()

// Get everything running
platformStartup()
}

deinit {
Self.removeActiveWriteKey(configuration.values.writeKey)
}

internal func process<E: RawEvent>(incomingEvent: E) {
guard enabled == true else { return }
let event = incomingEvent.applyRawEventData(store: store)

_ = timeline.process(incomingEvent: event)

let flushPolicies = configuration.values.flushPolicies
for policy in flushPolicies {
policy.updateState(event: event)

if (policy.shouldFlush() == true) {
flush()
policy.reset()
}
}
}

/// Process a raw event through the system. Useful when one needs to queue and replay events at a later time.
/// - Parameters:
/// - event: An event conforming to RawEvent that will be processed.
Expand Down Expand Up @@ -160,20 +161,20 @@ extension Analytics {
}
return ""
}

/// Returns the userId that was specified in the last identify call.
public var userId: String? {
if let userInfo: UserInfo = store.currentState() {
return userInfo.userId
}
return nil
}

/// Returns the current operating mode this instance was given.
public var operatingMode: OperatingMode {
return configuration.values.operatingMode
}

/// Adjusts the flush interval post configuration.
public var flushInterval: TimeInterval {
get {
Expand All @@ -186,7 +187,7 @@ extension Analytics {
}
}
}

/// Adjusts the flush-at count post configuration.
public var flushAt: Int {
get {
Expand All @@ -199,30 +200,30 @@ extension Analytics {
}
}
}

/// Returns a list of currently active flush policies.
public var flushPolicies: [FlushPolicy] {
get {
configuration.values.flushPolicies
}
}

/// Returns the traits that were specified in the last identify call.
public func traits<T: Codable>() -> T? {
if let userInfo: UserInfo = store.currentState() {
return userInfo.traits?.codableValue()
}
return nil
}

/// Returns the traits that were specified in the last identify call, as a dictionary.
public func traits() -> [String: Any]? {
if let userInfo: UserInfo = store.currentState() {
return userInfo.traits?.dictionaryValue
}
return nil
}

/// Tells this instance of Analytics to flush any queued events up to Segment.com. This command will also
/// be sent to each plugin present in the system. A completion handler can be optionally given and will be
/// called when flush has completed.
Expand All @@ -247,7 +248,7 @@ extension Analytics {
completion?()
}
}

/// Resets this instance of Analytics to a clean slate. Traits, UserID's, anonymousId, etc are all cleared or reset. This
/// command will also be sent to each plugin present in the system.
public func reset() {
Expand All @@ -258,13 +259,13 @@ extension Analytics {
}
}
}

/// Retrieve the version of this library in use.
/// - Returns: A string representing the version in "BREAKING.FEATURE.FIX" format.
public func version() -> String {
return Analytics.version()
}

/// Retrieve the version of this library in use.
/// - Returns: A string representing the version in "BREAKING.FEATURE.FIX" format.
public static func version() -> String {
Expand All @@ -282,7 +283,7 @@ extension Analytics {
}
return settings
}

/// Manually enable a destination plugin. This is useful when a given DestinationPlugin doesn't have any Segment tie-ins at all.
/// This will allow the destination to be processed in the same way within this library.
/// - Parameters:
Expand All @@ -306,25 +307,25 @@ extension Analytics {

return storage.dataStore.hasData
}

/// Provides a list of finished, but unsent events.
public var pendingUploads: [URL]? {
return storage.read(Storage.Constants.events)?.dataFiles
}

/// Purge all pending event upload files.
public func purgeStorage() {
storage.dataStore.reset()
}

/// Purge a single event upload file.
public func purgeStorage(fileURL: URL) {
guard let dataFiles = storage.read(Storage.Constants.events)?.dataFiles else { return }
if dataFiles.contains(fileURL) {
try? FileManager.default.removeItem(at: fileURL)
}
}

/// Wait until the Analytics object has completed startup.
/// This method is primarily useful for command line utilities where
/// it's desirable to wait until the system is up and running
Expand All @@ -344,7 +345,7 @@ extension Analytics {
Call openURL as needed or when instructed to by either UIApplicationDelegate or UISceneDelegate.
This is necessary to track URL referrers across events. This method will also iterate
any plugins that are watching for openURL events.

Example:
```
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
Expand All @@ -359,12 +360,12 @@ extension Analytics {
guard let dict = jsonProperties.dictionaryValue else { return }
openURL(url, options: dict)
}

/**
Call openURL as needed or when instructed to by either UIApplicationDelegate or UISceneDelegate.
This is necessary to track URL referrers across events. This method will also iterate
any plugins that are watching for openURL events.

Example:
```
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
Expand All @@ -375,14 +376,14 @@ extension Analytics {
*/
public func openURL(_ url: URL, options: [String: Any] = [:]) {
store.dispatch(action: UserInfo.SetReferrerAction(url: url))

// let any conforming plugins know
apply { plugin in
if let p = plugin as? OpeningURLs {
p.openURL(url, options: options)
}
}

var jsonProperties: JSON? = nil
if let json = try? JSON(options) {
jsonProperties = json
Expand Down Expand Up @@ -411,7 +412,7 @@ extension Analytics {
Self.firstInstance = self
}
}

/// Determines if an instance is dead.
internal var isDead: Bool {
return configuration.values.writeKey == Self.deadInstance
Expand Down Expand Up @@ -455,4 +456,3 @@ extension OperatingMode {
}
}
}

Loading

0 comments on commit 65b037e

Please sign in to comment.