From 8584012188f71a9e5ef981b94b94feca23d1baba Mon Sep 17 00:00:00 2001 From: kosyloa Date: Thu, 18 Apr 2024 15:54:06 +0200 Subject: [PATCH] Feature/get indexed if subscribed (#7) * feat: getIndexedEventsIfSubscribed * refactoring DXFeed files * refactoring promise add RequestProfile sample * add getTimeSeriesIfSubscribed * refactoring test: in separate files * skipping tests more correctly * errorchecker refactoring * fix exception test more sophisticated fetching opt value * remove useless nill exception * fix warnings --- DXFeedFramework.xcodeproj/project.pbxproj | 23 ++- DXFeedFramework/Api/DXFeed+LastEvents.swift | 82 +++++++++++ ...+LastEvent.swift => DXFeed+Promises.swift} | 0 DXFeedFramework/Api/DXFeed.swift | 42 ------ .../Osub/TimeSeriesSubscriptionSymbol.swift | 4 +- .../Extensions/MarketEvent+Access.swift | 8 ++ .../Native/Endpoint/NativeBuilder.swift | 2 +- .../Native/Endpoint/NativeEndpoint.swift | 10 +- .../Native/ErrorHandling/ErrorCheck.swift | 13 +- DXFeedFramework/Native/Feed/NativeFeed.swift | 113 +++++++++++---- DXFeedFramework/Native/Graal/Isolate.swift | 3 + .../Native/Ipf/Live/NativeExecutor.swift | 11 +- .../NativeInstrumentProfileCollector.swift | 8 +- .../NativeInstrumentProfileConnection.swift | 2 +- .../Ipf/Live/NativeProfileIterator.swift | 2 +- .../Ipf/NativeInstrumentProfileReader.swift | 30 ++-- .../Native/Promise/NativePromise.swift | 6 +- .../Native/QDS/NativeSymbolParser.swift | 2 +- .../Native/Schedule/NativeSchedule.swift | 26 ++-- .../Subscription/NativeSubscription.swift | 4 +- .../Native/Utils/NativeTimeFormat.swift | 12 +- .../Native/Utils/NativeTimePeriod.swift | 6 +- .../Native/Utils/NativeTimeZone.swift | 4 +- DXFeedFramework/Promise/Promise.swift | 6 +- DXFeedFramework/Utils/Optional+Ext.swift | 19 +++ DXFeedFrameworkTests/CandleTests.swift | 4 +- DXFeedFrameworkTests/DXAsyncLastTest.swift | 4 +- DXFeedFrameworkTests/DXAttachTest.swift | 92 ++++++------ DXFeedFrameworkTests/DXConnectionTest.swift | 2 +- DXFeedFrameworkTests/DXLastEventTest.swift | 18 --- .../DXLastEventsSubscribedTest.swift | 132 ++++++++++++++++++ .../DXOtcMarketOrderTest.swift | 2 +- DXFeedFrameworkTests/DXPromiseTest.swift | 10 +- DXFeedFrameworkTests/IsolateTest.swift | 3 +- .../RequestProfile.playground/Contents.swift | 10 ++ .../contents.xcplayground | 4 + .../QuoteTableViewController.swift | 4 +- 37 files changed, 516 insertions(+), 207 deletions(-) create mode 100644 DXFeedFramework/Api/DXFeed+LastEvents.swift rename DXFeedFramework/Api/{DXFeed+LastEvent.swift => DXFeed+Promises.swift} (100%) create mode 100644 DXFeedFramework/Utils/Optional+Ext.swift create mode 100644 DXFeedFrameworkTests/DXLastEventsSubscribedTest.swift create mode 100644 Samples/Playgrounds/RequestProfile.playground/Contents.swift create mode 100644 Samples/Playgrounds/RequestProfile.playground/contents.xcplayground diff --git a/DXFeedFramework.xcodeproj/project.pbxproj b/DXFeedFramework.xcodeproj/project.pbxproj index 10e7818e8..214b79e5e 100644 --- a/DXFeedFramework.xcodeproj/project.pbxproj +++ b/DXFeedFramework.xcodeproj/project.pbxproj @@ -108,6 +108,9 @@ 642DC93C2AAA22D900974F5C /* DXFeedFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 642DC9432AAA299800974F5C /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 646979712A3B5AF60003A9BA /* Colors.xcassets */; }; 642DC9442AAA29EA00974F5C /* IpfCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 642DC9402AAA290300974F5C /* IpfCell.swift */; }; + 6433B12D2BCE7ADD004EFED7 /* DXFeed+LastEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6433B12C2BCE7ADD004EFED7 /* DXFeed+LastEvents.swift */; }; + 6433B1322BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6433B1312BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift */; }; + 643A329B2BD0137000F6F790 /* Optional+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 643A329A2BD0137000F6F790 /* Optional+Ext.swift */; }; 64437A8F2A9DEE6F005929B2 /* InstrumentProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64437A8E2A9DEE6F005929B2 /* InstrumentProfile.swift */; }; 64437A922A9DF1DE005929B2 /* NativeInstrumentProfileReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64437A912A9DF1DE005929B2 /* NativeInstrumentProfileReader.swift */; }; 6447A5DB2A8E559000739CCF /* ILastingEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6447A5DA2A8E559000739CCF /* ILastingEvent.swift */; }; @@ -355,7 +358,7 @@ 64DA26C02AA224EB005B1757 /* NativeIPFConnectionListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DA26BF2AA224EB005B1757 /* NativeIPFConnectionListener.swift */; }; 64DB79342A376E1B00229597 /* DXFeedFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */; }; 64DB79352A376E1B00229597 /* DXFeedFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 64DF09332BC80DBB009F1486 /* DXFeed+LastEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DF09322BC80DBB009F1486 /* DXFeed+LastEvent.swift */; }; + 64DF09332BC80DBB009F1486 /* DXFeed+Promises.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DF09322BC80DBB009F1486 /* DXFeed+Promises.swift */; }; 64DF09352BC924AB009F1486 /* DXAsyncLastTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DF09342BC924AB009F1486 /* DXAsyncLastTest.swift */; }; 64E342502AAB083700457994 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6469F8D22A3B401700846831 /* Colors.swift */; }; 64E342522AAB29CF00457994 /* InstrumentProfileType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E342512AAB29CF00457994 /* InstrumentProfileType.swift */; }; @@ -662,7 +665,11 @@ 642DC9332AAA21C300974F5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 642DC9352AAA21C300974F5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 642DC9402AAA290300974F5C /* IpfCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IpfCell.swift; sourceTree = ""; }; + 6433B12C2BCE7ADD004EFED7 /* DXFeed+LastEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DXFeed+LastEvents.swift"; sourceTree = ""; }; + 6433B1302BCE87D4004EFED7 /* RequestProfile.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = RequestProfile.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 6433B1312BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXLastEventsSubscribedTest.swift; sourceTree = ""; }; 6435EE3C2B1F1E9200E8496C /* PrintQuoteEvents.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = PrintQuoteEvents.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 643A329A2BD0137000F6F790 /* Optional+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Ext.swift"; sourceTree = ""; }; 64437A8E2A9DEE6F005929B2 /* InstrumentProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstrumentProfile.swift; sourceTree = ""; }; 64437A912A9DF1DE005929B2 /* NativeInstrumentProfileReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeInstrumentProfileReader.swift; sourceTree = ""; }; 644551C92B973A0D0069E3A2 /* FetchDailyCandles.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = FetchDailyCandles.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -884,7 +891,7 @@ 64DA26BB2AA20B66005B1757 /* InstrumentProfileConnectionState+ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InstrumentProfileConnectionState+ext.swift"; sourceTree = ""; }; 64DA26BD2AA20EDB005B1757 /* DXInstrumentProfileConnectionListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXInstrumentProfileConnectionListener.swift; sourceTree = ""; }; 64DA26BF2AA224EB005B1757 /* NativeIPFConnectionListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeIPFConnectionListener.swift; sourceTree = ""; }; - 64DF09322BC80DBB009F1486 /* DXFeed+LastEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DXFeed+LastEvent.swift"; sourceTree = ""; }; + 64DF09322BC80DBB009F1486 /* DXFeed+Promises.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DXFeed+Promises.swift"; sourceTree = ""; }; 64DF09342BC924AB009F1486 /* DXAsyncLastTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXAsyncLastTest.swift; sourceTree = ""; }; 64E342512AAB29CF00457994 /* InstrumentProfileType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstrumentProfileType.swift; sourceTree = ""; }; 64E3637A2AD83459002E2B0D /* SeriesMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeriesMapper.swift; sourceTree = ""; }; @@ -1095,6 +1102,7 @@ 641C64AE2B344E770023CFAD /* PublishProfiles.playground */, 64F9C6C12B4BFD8F003ED014 /* DXFeedconnect.playground */, 644551C92B973A0D0069E3A2 /* FetchDailyCandles.playground */, + 6433B1302BCE87D4004EFED7 /* RequestProfile.playground */, ); path = Playgrounds; sourceTree = ""; @@ -1258,6 +1266,7 @@ 6464074E2A9F62D4006FF769 /* Date+Ext.swift */, 64A42F3A2B07A7A3001C3ACC /* SymbolParser.swift */, 640885C92B1F7EE700E6CF88 /* QdsUtils.swift */, + 643A329A2BD0137000F6F790 /* Optional+Ext.swift */, ); path = Utils; sourceTree = ""; @@ -1637,6 +1646,7 @@ 641C64B32B347C430023CFAD /* DXObservableSubscriptionTest.swift */, 6423E4682B457000006B208D /* DXTimeSeriesSubscriptionTest.swift */, 646064E92B4D8973009201E2 /* DXLastEventTest.swift */, + 6433B1312BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift */, 64EAA1A12B7A38F8005087BC /* DXPromiseTest.swift */, 64DF09342BC924AB009F1486 /* DXAsyncLastTest.swift */, 64EAA1A52B838ED3005087BC /* DXSnapshotProcessorTest.swift */, @@ -1703,7 +1713,8 @@ 64ACBCDB2A28974900032C53 /* Osub */, 80FC415829C8EE8B00E6B611 /* DXEndpoint.swift */, 64656F5A2A1B9784006A0B19 /* DXFeed.swift */, - 64DF09322BC80DBB009F1486 /* DXFeed+LastEvent.swift */, + 64DF09322BC80DBB009F1486 /* DXFeed+Promises.swift */, + 6433B12C2BCE7ADD004EFED7 /* DXFeed+LastEvents.swift */, 64656F662A1CCFC2006A0B19 /* DXPublisher.swift */, 64656F6C2A1CFB10006A0B19 /* DXEndpointState.swift */, 641BCBBB2A20ED8100FE23C2 /* DXEndpointListener.swift */, @@ -2171,6 +2182,7 @@ /* Begin PBXShellScriptBuildPhase section */ 64656F632A1BB22E006A0B19 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -2387,6 +2399,7 @@ 64BA92652A306E0200BE26A0 /* Trade.swift in Sources */, 6486B9752AD0493F00D8D5FA /* TheoPrice+Ext.swift in Sources */, 6464074B2A9DFAF7006FF769 /* InstrumentProfile+Ext.swift in Sources */, + 643A329B2BD0137000F6F790 /* Optional+Ext.swift in Sources */, 64C771F22A94A224009868C2 /* Character+Ext.swift in Sources */, 8088D77129C3A25D00F240CB /* SystemProperty.swift in Sources */, 640C3FD42A6179AB00555161 /* CandlePeriod.swift in Sources */, @@ -2508,7 +2521,7 @@ 80FC415F29CA2C5100E6B611 /* NativeProperty.swift in Sources */, 64656F622A1B9FF7006A0B19 /* EnumException.swift in Sources */, 641BCBC12A21077800FE23C2 /* EventCode.swift in Sources */, - 64DF09332BC80DBB009F1486 /* DXFeed+LastEvent.swift in Sources */, + 64DF09332BC80DBB009F1486 /* DXFeed+Promises.swift in Sources */, 64ACBCE82A28CF9700032C53 /* IndexedEventSubscriptionSymbol.swift in Sources */, 64C004782BA1C25C0009F7C9 /* OtcMarketsOrderMapper.swift in Sources */, 649F48882A615BED0016FDD1 /* CandleType.swift in Sources */, @@ -2531,6 +2544,7 @@ 64656F6B2A1CFAC2006A0B19 /* BridgeUtil.swift in Sources */, 64A42F3E2B07A807001C3ACC /* NativeSymbolParser.swift in Sources */, 8088D77329C3A2F400F240CB /* GraalException.swift in Sources */, + 6433B12D2BCE7ADD004EFED7 /* DXFeed+LastEvents.swift in Sources */, 64C004742BA09C110009F7C9 /* OtcMarketsOrder+Ext.swift in Sources */, 64C771FF2A9504ED009868C2 /* SnapshotProcessor.swift in Sources */, 64C771F82A94B88C009868C2 /* TimeAndSaleType.swift in Sources */, @@ -2585,6 +2599,7 @@ 649813C42ADD5CB2003CE3B3 /* TestEndpoointStateListener.swift in Sources */, 641C64B42B347C430023CFAD /* DXObservableSubscriptionTest.swift in Sources */, 64ACBCEC2A29FE2300032C53 /* XCTestCase+Utils.swift in Sources */, + 6433B1322BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift in Sources */, 6423E4692B457000006B208D /* DXTimeSeriesSubscriptionTest.swift in Sources */, 64ECD67F2A9CF4CB00B36935 /* IPFTests.swift in Sources */, 64ACBCD52A2789EF00032C53 /* TestListener.swift in Sources */, diff --git a/DXFeedFramework/Api/DXFeed+LastEvents.swift b/DXFeedFramework/Api/DXFeed+LastEvents.swift new file mode 100644 index 000000000..40b4b5128 --- /dev/null +++ b/DXFeedFramework/Api/DXFeed+LastEvents.swift @@ -0,0 +1,82 @@ +// +// +// Copyright (C) 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +import Foundation + +public extension DXFeed { + + /// Returns the last event for the specified event instance. + /// + /// This method works only for event types that implement ``ILastingEvent`` marker interface. + /// This method **does not** make any remote calls to the uplink data provider. + /// It just retrieves last received event from the local cache of this feed. + /// - Parameters: + /// - type: Type of MarketEvent. + /// - Returns: ``ILastingEvent`` + /// - Throws: ``GraalException``. Rethrows exception from Java. + func getLastEvent(type: MarketEvent) throws -> ILastingEvent? { + return try nativeFeed.getLastEvent(type: type) + } + + /// Returns the last events for the specified list of event instances. + /// + /// This is a bulk version of ``getLastEvent(type:)`` method. + /// - Parameters: + /// - types: The list of MarketEvent. + /// - Returns: The list of ``ILastingEvent`` + /// - Throws: ``GraalException``. Rethrows exception from Java. + func getLastEvents(types: [MarketEvent]) throws -> [ILastingEvent] { + return try nativeFeed.getLastEvents(types: types) + } +} + +public extension DXFeed { + /// Returns the last event for the specified event type and symbol if there is a subscription for it. + /// + /// This method works only for event types that implement ``ILastingEvent`` marker interface. + /// This method **does not** make any remote calls to the uplink data provider. + /// It just retrieves last received event from the local cache of this feed. + /// The events are stored in the cache only if there is some + /// attached ``DXFeedSubscription`` that is subscribed to the corresponding event type and symbol. + /// - Parameters: + /// - type: The event type ``IEventType``. + /// - symbol: The ``Symbol``. + /// - Returns: The list of ``ILastingEvent`` + /// - Throws: ``GraalException``. Rethrows exception from Java. + func getLastEventIfSubscribed(type: IEventType.Type, symbol: Symbol) throws -> ILastingEvent? { + return try nativeFeed.getLastEventIfSubscribed(type: type, symbol: symbol) + } + + // Returns a list of indexed events for the specified event type, symbol, and source + /// if there is a subscription for it. + /// + /// This method works only for event types that implement ``IIndexedEvent``interface. + /// This method **does not** make any remote calls to the uplink data provider. + /// It just retrieves last received events from the local cache of this feed. + /// The events are stored in the cache only if there is some + /// attached ``DXFeedSubscription`` that is subscribed to the corresponding event type, symbol, and source. + /// - Parameters: + /// - type: The event type ``IEventType``. + /// - symbol: The ``Symbol``. + /// - source: The ``IndexedEventSource``. + /// - Returns: The list of ``IIndexedEvent`` + /// - Throws: ``GraalException``. Rethrows exception from Java. + func getIndexedEventsIfSubscribed(type: IEventType.Type, + symbol: Symbol, + source: IndexedEventSource) throws -> [IIndexedEvent]? { + return try nativeFeed.getIndexedEventsIfSubscribed(type: type, + symbol: symbol, + source: source) + } + + func getTimeSeriesIfSubscribed(type: IEventType.Type, + symbol: Symbol, + fromTime: Long, + toTime: Long) throws -> [ITimeSeriesEvent]? { + return try nativeFeed.getTimeSeriesIfSubscribed(type: type, symbol: symbol, fromTime: fromTime, toTime: toTime) + } +} diff --git a/DXFeedFramework/Api/DXFeed+LastEvent.swift b/DXFeedFramework/Api/DXFeed+Promises.swift similarity index 100% rename from DXFeedFramework/Api/DXFeed+LastEvent.swift rename to DXFeedFramework/Api/DXFeed+Promises.swift diff --git a/DXFeedFramework/Api/DXFeed.swift b/DXFeedFramework/Api/DXFeed.swift index fcd0998af..5c6b01eaf 100644 --- a/DXFeedFramework/Api/DXFeed.swift +++ b/DXFeedFramework/Api/DXFeed.swift @@ -78,48 +78,6 @@ public class DXFeed { } } -public extension DXFeed { - - /// Returns the last event for the specified event instance. - /// - /// This method works only for event types that implement ``ILastingEvent`` marker interface. - /// This method **does not** make any remote calls to the uplink data provider. - /// It just retrieves last received event from the local cache of this feed. - /// - Parameters: - /// - type: Type of MarketEvent. - /// - Returns: ``ILastingEvent`` - /// - Throws: ``GraalException``. Rethrows exception from Java. - func getLastEvent(type: MarketEvent) throws -> ILastingEvent? { - return try native.getLastEvent(type: type) - } - - /// Returns the last event for the specified event type and symbol if there is a subscription for it. - /// This method works only for event types that implement ``ILastingEvent`` marker interface. - /// This method **does not** make any remote calls to the uplink data provider. - /// It just retrieves last received event from the local cache of this feed. - /// The events are stored in the cache only if there is some - /// attached ``DXFeedSubscription`` that is subscribed to the corresponding event type and symbol. - /// - Parameters: - /// - type: The event type ``IEventType``. - /// - symbol: The ``Symbol``. - /// - Returns: The list of ``ILastingEvent`` - /// - Throws: ``GraalException``. Rethrows exception from Java. - func getLastEventIfSubscribed(type: IEventType.Type, symbol: Symbol) throws -> ILastingEvent? { - return try native.getLastEventIfSubscribed(type: type, symbol: symbol) - } - - /// Returns the last events for the specified list of event instances. - /// - /// This is a bulk version of ``getLastEvent(type:)`` method. - /// - Parameters: - /// - types: The list of MarketEvent. - /// - Returns: The list of ``ILastingEvent`` - /// - Throws: ``GraalException``. Rethrows exception from Java. - func getLastEvents(types: [MarketEvent]) throws -> [ILastingEvent] { - return try native.getLastEvents(types: types) - } -} - public extension DXFeed { /// Attaches the given subscription to this feed. This method does nothing if the /// corresponding subscription is already attached to this feed. diff --git a/DXFeedFramework/Api/Osub/TimeSeriesSubscriptionSymbol.swift b/DXFeedFramework/Api/Osub/TimeSeriesSubscriptionSymbol.swift index fb66c667e..904df0b0d 100644 --- a/DXFeedFramework/Api/Osub/TimeSeriesSubscriptionSymbol.swift +++ b/DXFeedFramework/Api/Osub/TimeSeriesSubscriptionSymbol.swift @@ -52,7 +52,9 @@ public class TimeSeriesSubscriptionSymbol: GenericIndexedEventSubscriptionSymbol /// Custom symbol has to return string representation. public override var stringValue: String { - return "\(symbol.description){fromTime=\((try? DXTimeFormat.defaultTimeFormat?.withMillis?.format(value: fromTime)) ?? "")}" + return """ +\(symbol.description){fromTime=\((try? DXTimeFormat.defaultTimeFormat?.withMillis?.format(value: fromTime)) ?? "")} +""" } } diff --git a/DXFeedFramework/Events/Market/Extensions/MarketEvent+Access.swift b/DXFeedFramework/Events/Market/Extensions/MarketEvent+Access.swift index bbe5f1567..9a4d3f9cd 100644 --- a/DXFeedFramework/Events/Market/Extensions/MarketEvent+Access.swift +++ b/DXFeedFramework/Events/Market/Extensions/MarketEvent+Access.swift @@ -103,4 +103,12 @@ extension MarketEvent { return nil } } + + public var indexedEvent: IIndexedEvent? { + return self as? IIndexedEvent + } + + public var timeSeriesEvent: ITimeSeriesEvent? { + return self as? ITimeSeriesEvent + } } diff --git a/DXFeedFramework/Native/Endpoint/NativeBuilder.swift b/DXFeedFramework/Native/Endpoint/NativeBuilder.swift index 4ae938b1c..0e634e9bc 100644 --- a/DXFeedFramework/Native/Endpoint/NativeBuilder.swift +++ b/DXFeedFramework/Native/Endpoint/NativeBuilder.swift @@ -55,7 +55,7 @@ class NativeBuilder { func build() throws -> NativeEndpoint { let thread = currentThread() - let value = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_Builder_build(thread, builder)) + let value = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_Builder_build(thread, builder)).value() return NativeEndpoint(value) } } diff --git a/DXFeedFramework/Native/Endpoint/NativeEndpoint.swift b/DXFeedFramework/Native/Endpoint/NativeEndpoint.swift index 0a44645a1..728f8086d 100644 --- a/DXFeedFramework/Native/Endpoint/NativeEndpoint.swift +++ b/DXFeedFramework/Native/Endpoint/NativeEndpoint.swift @@ -42,7 +42,7 @@ class NativeEndpoint { private lazy var feed: NativeFeed? = { let thread = currentThread() do { - let nativeFeed = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_getFeed(thread, self.endpoint)) + let nativeFeed = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_getFeed(thread, self.endpoint)).value() return NativeFeed(feed: nativeFeed) } catch { return nil @@ -52,7 +52,9 @@ class NativeEndpoint { private lazy var publisher: NativePublisher? = { let thread = currentThread() do { - let nativeFeed = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_getPublisher(thread, self.endpoint)) + let nativeFeed = try ErrorCheck.nativeCall(thread, + dxfg_DXEndpoint_getPublisher(thread, + self.endpoint)).value() return NativePublisher(publisher: nativeFeed) } catch { return nil @@ -96,7 +98,7 @@ class NativeEndpoint { func getEventTypes() throws -> [EventCode] { let thread = currentThread() let list = try ErrorCheck.nativeCall(thread, dxfg_DXEndpoint_getEventTypes( - thread, endpoint)) + thread, endpoint)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_CList_EventClazz_release(thread, list)) @@ -121,7 +123,7 @@ class NativeEndpoint { let listener = try ErrorCheck.nativeCall(thread, dxfg_PropertyChangeListener_new(thread, NativeEndpoint.listenerCallback, - voidPtr)) + voidPtr)).value() self.listener = listener try ErrorCheck.nativeCall(thread, dxfg_Object_finalize(thread, &(listener.pointee.handler), diff --git a/DXFeedFramework/Native/ErrorHandling/ErrorCheck.swift b/DXFeedFramework/Native/ErrorHandling/ErrorCheck.swift index 93be1856e..16f7f0cda 100644 --- a/DXFeedFramework/Native/ErrorHandling/ErrorCheck.swift +++ b/DXFeedFramework/Native/ErrorHandling/ErrorCheck.swift @@ -44,16 +44,11 @@ class ErrorCheck { } } - static func nativeCall(_ thread: OpaquePointer!, _ result: T?) throws -> T { - if let result = result { - return result - } else { - if let exception = fetchException(thread) { - throw exception - } else { - throw GraalException.nullException - } + static func nativeCall(_ thread: OpaquePointer!, _ result: T) throws -> T { + if let exception = fetchException(thread) { + throw exception } + return result } static func graalCall(_ result: Int32) throws { diff --git a/DXFeedFramework/Native/Feed/NativeFeed.swift b/DXFeedFramework/Native/Feed/NativeFeed.swift index 4395ed1f6..3b62bf534 100644 --- a/DXFeedFramework/Native/Feed/NativeFeed.swift +++ b/DXFeedFramework/Native/Feed/NativeFeed.swift @@ -84,7 +84,7 @@ class NativeFeed { thread, type.eventSymbol, type.type.nativeCode()) - ) + ).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_EventType_release( @@ -101,26 +101,6 @@ class NativeFeed { return event?.lastingEvent } - func getLastEventIfSubscribed(type: IEventType.Type, symbol: Symbol) throws -> ILastingEvent? { - let thread = currentThread() - let converted = SymbolMapper.newNative(symbol) - defer { - if let converted = converted { - SymbolMapper.clearNative(symbol: converted) - } - } - do { - let result = try ErrorCheck.nativeCall(thread, - dxfg_DXFeed_getLastEventIfSubscribed(thread, - feed, - type.type.nativeCode(), - converted)) - return try mapper.fromNative(native: result)?.lastingEvent - } catch GraalException.nullException { - return nil - } - } - func getLastEvents(types: [MarketEvent]) throws -> [ILastingEvent] { let listPointer = UnsafeMutablePointer.allocate(capacity: 1) listPointer.pointee.size = Int32(types.count) @@ -176,7 +156,7 @@ class NativeFeed { dxfg_DXFeed_getLastEventPromise(thread, feed, type.type.nativeCode(), - converted)) + converted)).value() return NativePromise(promise: &native.pointee.handler) } @@ -195,7 +175,7 @@ class NativeFeed { dxfg_DXFeed_getLastEventsPromises(thread, feed, type.type.nativeCode(), - listPointer)) + listPointer)).value() var result = [NativePromise]() for index in 0.. ILastingEvent? { + let thread = currentThread() + let converted = SymbolMapper.newNative(symbol) + defer { + if let converted = converted { + SymbolMapper.clearNative(symbol: converted) + } + } + guard let result = try ErrorCheck.nativeCall(thread, + dxfg_DXFeed_getLastEventIfSubscribed(thread, + feed, + type.type.nativeCode(), + converted)) else { + return nil + } + return try mapper.fromNative(native: result)?.lastingEvent + } + + func getIndexedEventsIfSubscribed(type: IEventType.Type, + symbol: Symbol, + source: IndexedEventSource) throws -> [IIndexedEvent]? { + let thread = currentThread() + let converted = SymbolMapper.newNative(symbol) + defer { + if let converted = converted { + SymbolMapper.clearNative(symbol: converted) + } + } + guard let result = try ErrorCheck.nativeCall(thread, + dxfg_DXFeed_getIndexedEventsIfSubscribed( + thread, + feed, + type.type.nativeCode(), + converted, + source.name.toCStringRef())) else { + return nil + } + + let events: [IIndexedEvent] = + (0.. [ITimeSeriesEvent]? { + let thread = currentThread() + let converted = SymbolMapper.newNative(symbol) + defer { + if let converted = converted { + SymbolMapper.clearNative(symbol: converted) + } + } + guard let result = try ErrorCheck.nativeCall(thread, + dxfg_DXFeed_getTimeSeriesIfSubscribed( + thread, + feed, + type.type.nativeCode(), + converted, + fromTime, + toTime)) else { + return nil + } + let events: [ITimeSeriesEvent] = + (0.. NativeExecutor { let thread = currentThread() let executor = try ErrorCheck.nativeCall(thread, - dxfg_ExecutorBaseOnConcurrentLinkedQueue_new(thread)) + dxfg_ExecutorBaseOnConcurrentLinkedQueue_new(thread)).value() return NativeExecutor(executor: executor) } static func createOnScheduledThreadPool(numberOfThreads: Int32, nameOfthread: String) throws -> NativeExecutor { let thread = currentThread() let executor = try ErrorCheck.nativeCall(thread, - dxfg_Executors_newScheduledThreadPool(thread, - numberOfThreads, - nameOfthread.toCStringRef())) + dxfg_Executors_newScheduledThreadPool( + thread, + numberOfThreads, + nameOfthread.toCStringRef())).value() return NativeExecutor(executor: executor) } @@ -44,7 +45,7 @@ class NativeExecutor { let executor = try ErrorCheck.nativeCall(thread, dxfg_Executors_newFixedThreadPool(thread, numberOfThreads, - nameOfthread.toCStringRef())) + nameOfthread.toCStringRef())).value() return NativeExecutor(executor: executor) } } diff --git a/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileCollector.swift b/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileCollector.swift index 53dfe29a7..5881071a8 100644 --- a/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileCollector.swift +++ b/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileCollector.swift @@ -100,7 +100,7 @@ public class NativeInstrumentProfileCollector { func view() throws -> NativeProfileIterator { let thread = currentThread() - let native = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileCollector_view(thread, collector)) + let native = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileCollector_view(thread, collector)).value() return NativeProfileIterator(native, isDeallocated: true) } @@ -114,7 +114,9 @@ public class NativeInstrumentProfileCollector { func getExecutor() throws -> NativeExecutor { let thread = currentThread() - let native = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileCollector_getExecutor(thread, collector)) + let native = try ErrorCheck.nativeCall(thread, + dxfg_InstrumentProfileCollector_getExecutor(thread, + collector)).value() return NativeExecutor(executor: native) } @@ -132,7 +134,7 @@ public class NativeInstrumentProfileCollector { let nativeListener = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileUpdateListener_new(thread, callback, - voidPtr)) + voidPtr)).value() try ErrorCheck.nativeCall(thread, dxfg_Object_finalize(thread, &(nativeListener.pointee.handler), NativeInstrumentProfileCollector.finalizeCallback, diff --git a/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileConnection.swift b/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileConnection.swift index f6843ad06..1380c7b1c 100644 --- a/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileConnection.swift +++ b/DXFeedFramework/Native/Ipf/Live/NativeInstrumentProfileConnection.swift @@ -153,7 +153,7 @@ class NativeInstrumentProfileConnection { dxfg_IpfPropertyChangeListener_new( thread, NativeInstrumentProfileConnection.listenerCallback, - voidPtr)) + voidPtr)).value() try ErrorCheck.nativeCall(thread, dxfg_Object_finalize(thread, &(listener.pointee.handler), diff --git a/DXFeedFramework/Native/Ipf/Live/NativeProfileIterator.swift b/DXFeedFramework/Native/Ipf/Live/NativeProfileIterator.swift index 261d97ee0..57fd8efe8 100644 --- a/DXFeedFramework/Native/Ipf/Live/NativeProfileIterator.swift +++ b/DXFeedFramework/Native/Ipf/Live/NativeProfileIterator.swift @@ -34,7 +34,7 @@ class NativeProfileIterator { func next() throws -> InstrumentProfile { let thread = currentThread() - let result = try ErrorCheck.nativeCall(thread, dxfg_Iterable_InstrumentProfile_next(thread, iterator)) + let result = try ErrorCheck.nativeCall(thread, dxfg_Iterable_InstrumentProfile_next(thread, iterator)).value() let profile = mapper.fromNative(native: result) _ = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfile_release(thread, result)) diff --git a/DXFeedFramework/Native/Ipf/NativeInstrumentProfileReader.swift b/DXFeedFramework/Native/Ipf/NativeInstrumentProfileReader.swift index 4dfe2b7ee..c385ddfbf 100644 --- a/DXFeedFramework/Native/Ipf/NativeInstrumentProfileReader.swift +++ b/DXFeedFramework/Native/Ipf/NativeInstrumentProfileReader.swift @@ -42,9 +42,10 @@ class NativeInstrumentProfileReader { func readFromFile(address: String) throws -> [InstrumentProfile] { let thread = currentThread() let result = try ErrorCheck.nativeCall(thread, - dxfg_InstrumentProfileReader_readFromFile(thread, - reader, - address.toCStringRef())) + dxfg_InstrumentProfileReader_readFromFile( + thread, + reader, + address.toCStringRef())).value() let instruments = convertFromNativeList(result) _ = try ErrorCheck.nativeCall(thread, dxfg_CList_InstrumentProfile_release(thread, result)) return instruments @@ -53,11 +54,12 @@ class NativeInstrumentProfileReader { func readFromFile(address: String, user: String, password: String) throws -> [InstrumentProfile] { let thread = currentThread() let result = try ErrorCheck.nativeCall(thread, - dxfg_InstrumentProfileReader_readFromFile2(thread, - reader, - address.toCStringRef(), - user.toCStringRef(), - password.toCStringRef())) + dxfg_InstrumentProfileReader_readFromFile2( + thread, + reader, + address.toCStringRef(), + user.toCStringRef(), + password.toCStringRef())).value() let instruments = convertFromNativeList(result) _ = try ErrorCheck.nativeCall(thread, dxfg_CList_InstrumentProfile_release(thread, result)) return instruments @@ -96,14 +98,14 @@ class NativeInstrumentProfileReader { let inputStream = try ErrorCheck.nativeCall(thread, dxfg_ByteArrayInputStream_new(thread, pointer.baseAddress, - Int32(data.count))) + Int32(data.count))).value() return inputStream }) let result = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileReader_read2(thread, reader, inputStream, - address.toCStringRef())) + address.toCStringRef())).value() let instruments = convertFromNativeList(result) _ = try ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(inputStream.pointee.handler))) @@ -117,7 +119,7 @@ class NativeInstrumentProfileReader { let inputStream = try ErrorCheck.nativeCall(thread, dxfg_ByteArrayInputStream_new(thread, pointer.baseAddress, - Int32(data.count))) + Int32(data.count))).value() return inputStream }) @@ -125,7 +127,7 @@ class NativeInstrumentProfileReader { let result = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileReader_readCompressed(thread, reader, - inputStream)) + inputStream)).value() let instruments = convertFromNativeList(result) _ = try ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(inputStream.pointee.handler))) @@ -140,14 +142,14 @@ class NativeInstrumentProfileReader { let inputStream = try ErrorCheck.nativeCall(thread, dxfg_ByteArrayInputStream_new(thread, pointer.baseAddress, - Int32(data.count))) + Int32(data.count))).value() return inputStream }) let result = try ErrorCheck.nativeCall(thread, dxfg_InstrumentProfileReader_read(thread, reader, - inputStream)) + inputStream)).value() let instruments = convertFromNativeList(result) _ = try ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(inputStream.pointee.handler))) diff --git a/DXFeedFramework/Native/Promise/NativePromise.swift b/DXFeedFramework/Native/Promise/NativePromise.swift index 7faf8d039..acae44dc5 100644 --- a/DXFeedFramework/Native/Promise/NativePromise.swift +++ b/DXFeedFramework/Native/Promise/NativePromise.swift @@ -72,7 +72,7 @@ class NativePromise { let res = try promise?.withMemoryRebound(to: dxfg_promise_events_t.self, capacity: 1, { promiseEvents in let listPointer = try ErrorCheck.nativeCall(thread, dxfg_Promise_List_EventType_getResult(thread, - promiseEvents)) + promiseEvents)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_CList_EventType_release(thread, listPointer)) } @@ -97,7 +97,9 @@ class NativePromise { } let thread = currentThread() let res = try promise?.withMemoryRebound(to: dxfg_promise_event_t.self, capacity: 1, { promiseEvent in - let result = try ErrorCheck.nativeCall(thread, dxfg_Promise_EventType_getResult(thread, promiseEvent)) + let result = try ErrorCheck.nativeCall(thread, + dxfg_Promise_EventType_getResult(thread, + promiseEvent)).value() let marketEvent = try EventMapper().fromNative(native: result) defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_EventType_release(thread, result)) diff --git a/DXFeedFramework/Native/QDS/NativeSymbolParser.swift b/DXFeedFramework/Native/QDS/NativeSymbolParser.swift index 9fd8237c1..75e58a575 100644 --- a/DXFeedFramework/Native/QDS/NativeSymbolParser.swift +++ b/DXFeedFramework/Native/QDS/NativeSymbolParser.swift @@ -10,7 +10,7 @@ import Foundation class NativeSymbolParser { func parse(_ symbols: String) throws -> [String] { let thread = currentThread() - let symbols = try ErrorCheck.nativeCall(thread, dxfg_Tools_parseSymbols(thread, symbols.toCStringRef())) + let symbols = try ErrorCheck.nativeCall(thread, dxfg_Tools_parseSymbols(thread, symbols.toCStringRef())).value() var result = [String]() for index in 0.. ScheduleDay { let thread = currentThread() - let day = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getDayByTime(thread, schedule, time)) + let day = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getDayByTime(thread, schedule, time)).value() return try createDay(thread, day) } public func getDayById(dayId: Int32) throws -> ScheduleDay { let thread = currentThread() - let day = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getDayById(thread, schedule, dayId)) + let day = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getDayById(thread, schedule, dayId)).value() return try createDay(thread, day) } public func getDayByYearMonthDay(yearMonthDay: Int32) throws -> ScheduleDay { let thread = currentThread() - let day = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getDayByYearMonthDay(thread, schedule, yearMonthDay)) + let day = try ErrorCheck.nativeCall(thread, + dxfg_Schedule_getDayByYearMonthDay(thread, + schedule, + yearMonthDay)).value() return try createDay(thread, day) } @@ -124,7 +127,7 @@ class NativeSchedule { scheduleDay.trading = try ErrorCheck.nativeCall(thread, dxfg_Day_isTrading(thread, day)) scheduleDay.startTime = try ErrorCheck.nativeCall(thread, dxfg_Day_getStartTime(thread, day)) scheduleDay.endTime = try ErrorCheck.nativeCall(thread, dxfg_Day_getEndTime(thread, day)) - let sessions = try ErrorCheck.nativeCall(thread, dxfg_Day_getSessions(thread, day)) + let sessions = try ErrorCheck.nativeCall(thread, dxfg_Day_getSessions(thread, day)).value() let count = sessions.pointee.size for index in 0.. ScheduleDay? { let qdValue = filter.toQDValue() let thread = currentThread() - let filter = try ErrorCheck.nativeCall(thread, dxfg_DayFilter_getInstance(thread, qdValue)) + let filter = try ErrorCheck.nativeCall(thread, dxfg_DayFilter_getInstance(thread, qdValue)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(filter.pointee.handler))) } @@ -212,7 +215,7 @@ class NativeSchedule { executor: GetSessionyExecutor) throws -> ScheduleSession? { let qdValue = filter.toQDValue() let thread = currentThread() - let filter = try ErrorCheck.nativeCall(thread, dxfg_SessionFilter_getInstance(thread, qdValue)) + let filter = try ErrorCheck.nativeCall(thread, dxfg_SessionFilter_getInstance(thread, qdValue)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(filter.pointee.handler))) } @@ -223,7 +226,10 @@ class NativeSchedule { public func getSessionByTime(time: Long) throws -> ScheduleSession { let thread = currentThread() - let nextSession = try ErrorCheck.nativeCall(thread, dxfg_Schedule_getSessionByTime(thread, schedule, time)) + let nextSession = try ErrorCheck.nativeCall(thread, + dxfg_Schedule_getSessionByTime(thread, + schedule, + time)).value() let session = try createSession(thread, session: nextSession) return session } @@ -231,7 +237,7 @@ class NativeSchedule { public func getNearestSessionByTime(time: Long, filter: SessionFilter) throws -> ScheduleSession { let qdValue = filter.toQDValue() let thread = currentThread() - let filter = try ErrorCheck.nativeCall(thread, dxfg_SessionFilter_getInstance(thread, qdValue)) + let filter = try ErrorCheck.nativeCall(thread, dxfg_SessionFilter_getInstance(thread, qdValue)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_JavaObjectHandler_release(thread, &(filter.pointee.handler))) } @@ -239,7 +245,7 @@ class NativeSchedule { dxfg_Schedule_getNearestSessionByTime(thread, schedule, time, - filter)) + filter)).value() let session = try createSession(thread, session: nextSession) return session } diff --git a/DXFeedFramework/Native/Subscription/NativeSubscription.swift b/DXFeedFramework/Native/Subscription/NativeSubscription.swift index 9c0e005bf..d1b585f21 100644 --- a/DXFeedFramework/Native/Subscription/NativeSubscription.swift +++ b/DXFeedFramework/Native/Subscription/NativeSubscription.swift @@ -149,7 +149,7 @@ class NativeSubscription { let listener = try ErrorCheck.nativeCall(thread, dxfg_DXFeedEventListener_new(thread, NativeSubscription.listenerCallback, - voidPtr)) + voidPtr)).value() try ErrorCheck.nativeCall(thread, dxfg_Object_finalize(thread, &(listener.pointee.handler), @@ -285,7 +285,7 @@ extension NativeSubscription { let thread = currentThread() let nativeResult = try ErrorCheck.nativeCall(thread, dxfg_DXFeedSubscription_getSymbols(thread, - self.subscription)) + self.subscription)).value() defer { _ = try? ErrorCheck.nativeCall(thread, dxfg_CList_symbol_release(thread, nativeResult)) } diff --git a/DXFeedFramework/Native/Utils/NativeTimeFormat.swift b/DXFeedFramework/Native/Utils/NativeTimeFormat.swift index 2b998a3b0..b5c1d279d 100644 --- a/DXFeedFramework/Native/Utils/NativeTimeFormat.swift +++ b/DXFeedFramework/Native/Utils/NativeTimeFormat.swift @@ -33,25 +33,29 @@ class NativeTimeFormat: NativeBox { convenience init(timeZone: NativeTimeZone) throws { let thread = currentThread() - let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_getInstance(thread, timeZone.native)) + let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_getInstance(thread, timeZone.native)).value() self.init(native: timeFormat) } convenience init(withTimeZone timeFormat: NativeTimeFormat) throws { let thread = currentThread() - let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_withTimeZone(thread, timeFormat.native)) + let timeFormat = try ErrorCheck.nativeCall(thread, + dxfg_TimeFormat_withTimeZone(thread, + timeFormat.native)).value() self.init(native: timeFormat) } convenience init(withMillis timeFormat: NativeTimeFormat) throws { let thread = currentThread() - let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_withMillis(thread, timeFormat.native)) + let timeFormat = try ErrorCheck.nativeCall(thread, + dxfg_TimeFormat_withMillis(thread, + timeFormat.native)).value() self.init(native: timeFormat) } convenience init(fullIso timeFormat: NativeTimeFormat) throws { let thread = currentThread() - let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_asFullIso(thread, timeFormat.native)) + let timeFormat = try ErrorCheck.nativeCall(thread, dxfg_TimeFormat_asFullIso(thread, timeFormat.native)).value() self.init(native: timeFormat) } diff --git a/DXFeedFramework/Native/Utils/NativeTimePeriod.swift b/DXFeedFramework/Native/Utils/NativeTimePeriod.swift index d3c34eb14..0ff261ddb 100644 --- a/DXFeedFramework/Native/Utils/NativeTimePeriod.swift +++ b/DXFeedFramework/Native/Utils/NativeTimePeriod.swift @@ -33,13 +33,15 @@ class NativeTimePeriod: NativeBox { convenience init(value: Int64) throws { let thread = currentThread() - let timePeriod = try ErrorCheck.nativeCall(thread, dxfg_TimePeriod_valueOf(thread, value)) + let timePeriod = try ErrorCheck.nativeCall(thread, dxfg_TimePeriod_valueOf(thread, value)).value() self.init(native: timePeriod) } convenience init(value: String) throws { let thread = currentThread() - let timePeriod = try ErrorCheck.nativeCall(thread, dxfg_TimePeriod_valueOf2(thread, value.toCStringRef())) + let timePeriod = try ErrorCheck.nativeCall(thread, + dxfg_TimePeriod_valueOf2(thread, + value.toCStringRef())).value() self.init(native: timePeriod) } diff --git a/DXFeedFramework/Native/Utils/NativeTimeZone.swift b/DXFeedFramework/Native/Utils/NativeTimeZone.swift index 71aeff17c..086999487 100644 --- a/DXFeedFramework/Native/Utils/NativeTimeZone.swift +++ b/DXFeedFramework/Native/Utils/NativeTimeZone.swift @@ -24,7 +24,9 @@ class NativeTimeZone: NativeBox { convenience init(timeZoneID: String) throws { let thread = currentThread() - let native = try ErrorCheck.nativeCall(thread, dxfg_TimeZone_getTimeZone(thread, timeZoneID.toCStringRef())) + let native = try ErrorCheck.nativeCall(thread, + dxfg_TimeZone_getTimeZone(thread, + timeZoneID.toCStringRef())).value() self.init(native: native) } diff --git a/DXFeedFramework/Promise/Promise.swift b/DXFeedFramework/Promise/Promise.swift index a6661995c..b63604f3b 100644 --- a/DXFeedFramework/Promise/Promise.swift +++ b/DXFeedFramework/Promise/Promise.swift @@ -69,16 +69,18 @@ public class Promise { /// This method waits forever. /// - Returns: result of computation. /// - Throws : GraalException. Rethrows exception from Java - public func await() throws { + @discardableResult public func await() throws -> Promise { _ = try native.await() + return self } /// Wait for computation to complete and return its result or throw an exception in case of exceptional completion. /// If the wait times out, then the computation is ``cancel()`` cancelled and exception is thrown. /// - Returns: result of computation. /// - Throws : GraalException. Rethrows exception from Java - public func await(millis timeOut: Int32) throws { + @discardableResult public func await(millis timeOut: Int32) throws -> Promise { _ = try native.await(millis: timeOut) + return self } /// Wait for computation to complete and return its result or throw an exception in case of exceptional completion. /// If the wait times out, then the computation is ``cancel()`` cancelled and exception is thrown. diff --git a/DXFeedFramework/Utils/Optional+Ext.swift b/DXFeedFramework/Utils/Optional+Ext.swift new file mode 100644 index 000000000..a24e6b75c --- /dev/null +++ b/DXFeedFramework/Utils/Optional+Ext.swift @@ -0,0 +1,19 @@ +// +// +// Copyright (C) 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +import Foundation + +extension Optional { + func value() throws -> Wrapped { + switch self { + case .none: + throw GraalException.nullException + case .some(let val): + return val + } + } +} diff --git a/DXFeedFrameworkTests/CandleTests.swift b/DXFeedFrameworkTests/CandleTests.swift index ab93106bf..5eaf4c99d 100644 --- a/DXFeedFrameworkTests/CandleTests.swift +++ b/DXFeedFrameworkTests/CandleTests.swift @@ -264,7 +264,9 @@ final class CandleTests: XCTestCase { XCTAssertEqual("EUR/USD{=2h,price=bid,source=bank}", CandleSymbol.valueOf("EUR/USD{source=bank}", - [CandlePrice.bid, CandlePeriod.valueOf(value: 2, type: CandleType.hour)]).toString()) + [CandlePrice.bid, + CandlePeriod.valueOf(value: 2, type: CandleType.hour)] + ).toString()) XCTAssertEqual("IBM{=15m,aa=zz,price=bid}", CandleSymbol.valueOf("IBM{aa=zz,price=b}", [CandlePeriod.valueOf(value: 15, type: CandleType.minute)]).toString()) diff --git a/DXFeedFrameworkTests/DXAsyncLastTest.swift b/DXFeedFrameworkTests/DXAsyncLastTest.swift index e123f0eca..d574123ce 100644 --- a/DXFeedFrameworkTests/DXAsyncLastTest.swift +++ b/DXFeedFrameworkTests/DXAsyncLastTest.swift @@ -93,10 +93,10 @@ final class DXAsyncLastTest: XCTestCase { } func testIndexedEventTask() async throws { - throw XCTSkip(""" + // just use it to avoid warnings + try XCTSkipIf(true, """ Skiped """) - let date = Calendar.current.date(byAdding: .month, value: -1, to: Date())! guard let task = feed?.getIndexedEvents(type: Series.self, symbol: "ETH/USD:GDAX", source: OrderSource.agregateAsk!) else { diff --git a/DXFeedFrameworkTests/DXAttachTest.swift b/DXFeedFrameworkTests/DXAttachTest.swift index c56f31c59..1bc25c224 100644 --- a/DXFeedFrameworkTests/DXAttachTest.swift +++ b/DXFeedFrameworkTests/DXAttachTest.swift @@ -11,59 +11,63 @@ import XCTest final class DXAttachTest: XCTestCase { let detachedSymbol = "TEST1" let attachedSymbol = "TEST2" + var endpoint: DXEndpoint! + var feed: DXFeed! + var publisher: DXPublisher! + + override func setUpWithError() throws { + endpoint = try DXEndpoint.create() + feed = endpoint.getFeed() + publisher = endpoint.getPublisher() + } func testAttachDetach() throws { - let endpoint = try DXEndpoint.create() do { - if let feed = endpoint.getFeed(), let publisher = endpoint.getPublisher() { - let subcription = try feed.createSubscription([TimeAndSale.self]) - let expectation1 = expectation(description: "Events received") - let expectation2 = expectation(description: "Events received") - let listener = AnonymousClass { anonymCl in - anonymCl.callback = { events in - events.forEach { event in - switch event.eventSymbol { - case self.detachedSymbol: - XCTFail("Received detached symbol \(event.toString())") - case self.attachedSymbol: - if event.timeAndSale.askPrice == 100 { - expectation1.fulfill() - } else if event.timeAndSale.askPrice == 200 { - expectation2.fulfill() - } - default: - XCTFail("Unexpected symbol \(event.toString())") + let subcription = try feed.createSubscription([TimeAndSale.self]) + let expectation1 = expectation(description: "Events received") + let expectation2 = expectation(description: "Events received") + let listener = AnonymousClass { anonymCl in + anonymCl.callback = { events in + events.forEach { event in + switch event.eventSymbol { + case self.detachedSymbol: + XCTFail("Received detached symbol \(event.toString())") + case self.attachedSymbol: + if event.timeAndSale.askPrice == 100 { + expectation1.fulfill() + } else if event.timeAndSale.askPrice == 200 { + expectation2.fulfill() } + default: + XCTFail("Unexpected symbol \(event.toString())") } } - return anonymCl } - try subcription.add(listener: listener) - try subcription.addSymbols(detachedSymbol) - try feed.detach(subscription: subcription) - try publisher.publish(events: [TimeAndSale(detachedSymbol)]) - try feed.attach(subscription: subcription) - try feed.attach(subscription: subcription) - try subcription.addSymbols(attachedSymbol) + return anonymCl + } + try subcription.add(listener: listener) + try subcription.addSymbols(detachedSymbol) + try feed.detach(subscription: subcription) + try publisher.publish(events: [TimeAndSale(detachedSymbol)]) + try feed.attach(subscription: subcription) + try feed.attach(subscription: subcription) + try subcription.addSymbols(attachedSymbol) - try publisher.publish(events: [TimeAndSale(attachedSymbol).also(block: { tns in - tns.askPrice = 100 - })]) - wait(for: [expectation1], timeout: 1) - try subcription.detach(feed: feed) - try publisher.publish(events: [TimeAndSale(detachedSymbol)]) - try subcription.attach(feed: feed) - try publisher.publish(events: [TimeAndSale(attachedSymbol).also(block: { tns in - tns.askPrice = 200 - })]) - wait(for: [expectation2], timeout: 1) - let symbols = try subcription.getSymbols().map { symbol in - symbol.stringValue - } - XCTAssert(Set(symbols) == Set([attachedSymbol, detachedSymbol])) - } else { - XCTAssert(false, "Subscription returned null") + try publisher.publish(events: [TimeAndSale(attachedSymbol).also(block: { tns in + tns.askPrice = 100 + })]) + wait(for: [expectation1], timeout: 1) + try subcription.detach(feed: feed) + try publisher.publish(events: [TimeAndSale(detachedSymbol)]) + try subcription.attach(feed: feed) + try publisher.publish(events: [TimeAndSale(attachedSymbol).also(block: { tns in + tns.askPrice = 200 + })]) + wait(for: [expectation2], timeout: 1) + let symbols = try subcription.getSymbols().map { symbol in + symbol.stringValue } + XCTAssert(Set(symbols) == Set([attachedSymbol, detachedSymbol])) } catch { XCTAssert(false, "Error during attach/detach \(error)") } diff --git a/DXFeedFrameworkTests/DXConnectionTest.swift b/DXFeedFrameworkTests/DXConnectionTest.swift index 9129863a6..d50a5103f 100644 --- a/DXFeedFrameworkTests/DXConnectionTest.swift +++ b/DXFeedFrameworkTests/DXConnectionTest.swift @@ -35,7 +35,7 @@ extension DXConnectionListener: Hashable { } final class DXConnectionTest: XCTestCase { - override class func setUp() { + override func setUpWithError() throws { // The experimental property must be enabled. try? SystemProperty.setProperty("dxfeed.experimental.dxlink.enable", "true") // Set scheme for dxLink. diff --git a/DXFeedFrameworkTests/DXLastEventTest.swift b/DXFeedFrameworkTests/DXLastEventTest.swift index 1cdced72f..7e9b34413 100644 --- a/DXFeedFrameworkTests/DXLastEventTest.swift +++ b/DXFeedFrameworkTests/DXLastEventTest.swift @@ -152,22 +152,4 @@ final class DXLastEventTest: XCTestCase { } } - func testGetLastEventIfSubscribed() throws { - let testSymbol = StringUtil.random(length: 5) - let endpoint: DXEndpoint? = try DXEndpoint.create(.localHub) - let feed = endpoint?.getFeed() - let publisher = endpoint?.getPublisher() - let quote = try feed?.getLastEventIfSubscribed(type: Quote.self, symbol: testSymbol) - XCTAssertNil(quote) - let subscription = try feed?.createSubscription([Quote.self]) - try subscription?.addSymbols(testSymbol) - try publisher?.publish(events: [Quote(testSymbol).also(block: { quote in - quote.askPrice = 101 - })]) - let existingQuotes = try feed?.getLastEventIfSubscribed(type: Quote.self, symbol: testSymbol) - XCTAssertNotNil(existingQuotes) - XCTAssertEqual(101, (existingQuotes as? Quote)?.askPrice) - - } - } diff --git a/DXFeedFrameworkTests/DXLastEventsSubscribedTest.swift b/DXFeedFrameworkTests/DXLastEventsSubscribedTest.swift new file mode 100644 index 000000000..146364652 --- /dev/null +++ b/DXFeedFrameworkTests/DXLastEventsSubscribedTest.swift @@ -0,0 +1,132 @@ +// +// +// Copyright (C) 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +import XCTest +@testable import DXFeedFramework + +final class DXLastEventsSubscribedTest: XCTestCase { + var endpoint: DXEndpoint? + var feed: DXFeed? + var publisher: DXPublisher? + + override func setUpWithError() throws { + endpoint = try DXEndpoint.create(.localHub) + feed = endpoint?.getFeed() + publisher = endpoint?.getPublisher() + } + + override func tearDownWithError() throws { + try endpoint?.closeAndAwaitTermination() + } + + func testGetLastEventIfSubscribed() throws { + let testSymbol = StringUtil.random(length: 5) + + let quote = try feed?.getLastEventIfSubscribed(type: Quote.self, symbol: testSymbol) + XCTAssertNil(quote) + let subscription = try feed?.createSubscription([Quote.self]) + try subscription?.addSymbols(testSymbol) + try publisher?.publish(events: [Quote(testSymbol).also(block: { quote in + quote.askPrice = 101 + })]) + let existingQuotes = try feed?.getLastEventIfSubscribed(type: Quote.self, symbol: testSymbol) + XCTAssertNotNil(existingQuotes) + XCTAssertEqual(101, (existingQuotes as? Quote)?.askPrice) + } + + func testGetIndexedEventsIfSubscribed() throws { + let testSymbol = StringUtil.random(length: 5) + let type = Order.self + let nillOrderList = try feed?.getIndexedEventsIfSubscribed(type: type, + symbol: testSymbol, + source: .defaultSource) + XCTAssertNotNil(nillOrderList) + // should be nill +// XCTAssertNil(nillOrderList) + let subscription = try feed?.createSubscription([type]) + try subscription?.addSymbols(testSymbol) + let emptyOrderList = try feed?.getIndexedEventsIfSubscribed(type: type, + symbol: testSymbol, + source: .defaultSource) + XCTAssertNotNil(emptyOrderList) + + try publisher?.publish(events: [Order(testSymbol).also(block: { order in + try? order.setIndex(1) + order.orderSide = .buy + order.price = 10.5 + order.size = 100 + })]) + let orderList = try feed?.getIndexedEventsIfSubscribed(type: type, symbol: testSymbol, source: .defaultSource) + XCTAssertEqual(1, orderList?.count) + let order = orderList?.first as? Order + XCTAssertNotNil(order) + XCTAssertEqual(1, order?.index) + XCTAssertEqual(Side.buy, order?.orderSide) + XCTAssertEqual(10.5, order?.price) + XCTAssertEqual(100, order?.size) + } + + func testGetTimeSeriesIfSubscribed() throws { + let candleSymbol = CandleSymbol.valueOf( StringUtil.random(length: 5), [CandlePeriod.day]) + guard let fromTime: Long = try DXTimeFormat.defaultTimeFormat?.parse("20150101"), + let toTime: Long = try DXTimeFormat.defaultTimeFormat?.parse("20150710") else { + XCTAssert(false, "Parsing failed") + return + } + let type = Candle.self + + do { + let nillList = try feed?.getTimeSeriesIfSubscribed(type: type, + symbol: candleSymbol, + fromTime: fromTime, + toTime: toTime) + XCTAssertNotNil(nillList) + // should be nill +// XCTAssertNil(nillList) + } + let subscription = try feed?.createSubscription([type]) + do { + // wrong sub time + try subscription?.addSymbols(TimeSeriesSubscriptionSymbol(symbol: candleSymbol, fromTime: toTime)) + let nillList = try feed?.getTimeSeriesIfSubscribed(type: type, + symbol: candleSymbol, + fromTime: fromTime, + toTime: toTime) + XCTAssertNotNil(nillList) + // should be nill +// XCTAssertNil(nillList) + } + do { + // right sub time + try subscription?.addSymbols(TimeSeriesSubscriptionSymbol(symbol: candleSymbol, fromTime: fromTime)) + let nillList = try feed?.getTimeSeriesIfSubscribed(type: type, + symbol: candleSymbol, + fromTime: fromTime, + toTime: toTime) + XCTAssertNotNil(nillList) + } + do { + // publish something + try publisher?.publish(events: [Candle(candleSymbol).also(block: { candle in + candle.time = fromTime + candle.close = 10.5 + candle.volume = 100 + })]) + let list = try feed?.getTimeSeriesIfSubscribed(type: type, + symbol: candleSymbol, + fromTime: fromTime, + toTime: toTime) + XCTAssertEqual(1, list?.count) + let candle = list?.first as? Candle + XCTAssertNotNil(candle) + XCTAssertEqual(fromTime, candle?.time) + XCTAssertEqual(10.5, candle?.close) + XCTAssertEqual(100, candle?.volume) + } + } + +} diff --git a/DXFeedFrameworkTests/DXOtcMarketOrderTest.swift b/DXFeedFrameworkTests/DXOtcMarketOrderTest.swift index 5ff422eb1..2099f2a4d 100644 --- a/DXFeedFrameworkTests/DXOtcMarketOrderTest.swift +++ b/DXFeedFrameworkTests/DXOtcMarketOrderTest.swift @@ -71,7 +71,7 @@ final class DXOtcMarketOrderTest: XCTestCase { if events.count > 0 { events.forEach { event in XCTAssertEqual(event.type, .otcMarketsOrder) - var event = event.otcMarketsOrder + let event = event.otcMarketsOrder if event.eventSymbol == SYMBOL1 { XCTAssertEqual(event.marketMaker, "MM1") XCTAssertEqual(event.price, 10) diff --git a/DXFeedFrameworkTests/DXPromiseTest.swift b/DXFeedFrameworkTests/DXPromiseTest.swift index a2daa3609..fa1bf7270 100644 --- a/DXFeedFrameworkTests/DXPromiseTest.swift +++ b/DXFeedFrameworkTests/DXPromiseTest.swift @@ -84,7 +84,7 @@ final class DXPromiseTest: XCTestCase { receivedEventExp.fulfill() } } - wait(for: [receivedEventExp], timeout: 1) + wait(for: [receivedEventExp], timeout: 2) } catch { XCTAssert(false, "testGetResult \(error)") @@ -177,7 +177,7 @@ final class DXPromiseTest: XCTestCase { } } }) - wait(for: Array(expectations.values), timeout: 1) + wait(for: Array(expectations.values), timeout: 2) } catch { XCTAssert(false, "testGetIndexedEventResult \(error)") } @@ -186,7 +186,8 @@ final class DXPromiseTest: XCTestCase { func testGetMultipleResultsWithException() { do { - let promises = try feed?.getLastEventsPromises(type: Quote.self, symbols: ["ETH/USD:GDAX_TEST", "AAPL_TEST"]) + let promises = try feed?.getLastEventsPromises(type: Quote.self, + symbols: ["ETH/USD:GDAX_TEST", "AAPL_TEST"]) if promises?.isEmpty != false { XCTAssert(false, "Promises is empty") } @@ -274,7 +275,8 @@ final class DXPromiseTest: XCTestCase { } func testCompleteExceptPromise() throws { - throw XCTSkip(""" + // just use it to avoid warnings + try XCTSkipIf(true, """ Graal doesn't have impl for ExceptionMapper.toJava. and always throws exception illegalStateException """) diff --git a/DXFeedFrameworkTests/IsolateTest.swift b/DXFeedFrameworkTests/IsolateTest.swift index c1f7ad7f6..454fe56ce 100644 --- a/DXFeedFrameworkTests/IsolateTest.swift +++ b/DXFeedFrameworkTests/IsolateTest.swift @@ -18,7 +18,8 @@ final class IsolateTest: XCTestCase { } func testCleanup() throws { - throw XCTSkip("Just for manual running") + // just use it to avoid warnings + try XCTSkipIf(true, "Just for manual running") let isolate = Isolate.shared isolate.cleanup() let sec = 5 diff --git a/Samples/Playgrounds/RequestProfile.playground/Contents.swift b/Samples/Playgrounds/RequestProfile.playground/Contents.swift new file mode 100644 index 000000000..4c45a5ac6 --- /dev/null +++ b/Samples/Playgrounds/RequestProfile.playground/Contents.swift @@ -0,0 +1,10 @@ +import Cocoa +import DXFeedFramework + +let address = "demo.dxfeed.com:7300" +let symbol = "AAPL" +let endpoint = try DXEndpoint.create().connect(address) +let promise = try endpoint.getFeed()?.getLastEventPromise(type: Profile.self, symbol: symbol) +let profile = try promise?.await(millis: 5000).getResult() +print(profile?.toString()) +try endpoint.closeAndAwaitTermination() diff --git a/Samples/Playgrounds/RequestProfile.playground/contents.xcplayground b/Samples/Playgrounds/RequestProfile.playground/contents.xcplayground new file mode 100644 index 000000000..1c968e7d1 --- /dev/null +++ b/Samples/Playgrounds/RequestProfile.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Samples/QuoteTableApp/QuoteTableViewController.swift b/Samples/QuoteTableApp/QuoteTableViewController.swift index a3825f359..3881b4fd3 100644 --- a/Samples/QuoteTableApp/QuoteTableViewController.swift +++ b/Samples/QuoteTableApp/QuoteTableViewController.swift @@ -29,7 +29,9 @@ class QuoteTableViewController: UIViewController { quoteTableView.separatorStyle = .none - NotificationCenter.default.addObserver(forName: .selectedSymbolsChanged, object: nil, queue: nil) { [weak self] (_) in + NotificationCenter.default.addObserver(forName: .selectedSymbolsChanged, + object: nil, + queue: nil) { [weak self] (_) in guard let strongSelf = self else { return }