Handling for websocket
This commit is contained in:
@@ -15,6 +15,7 @@ public protocol Credential {
|
||||
var appSecret: String { get }
|
||||
}
|
||||
|
||||
|
||||
extension String {
|
||||
var digitsOnly: String { filter { ("0"..."9").contains($0) } }
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ public protocol Request {
|
||||
var timeout: TimeInterval { get }
|
||||
var responseDataLoggable: Bool { get }
|
||||
var traceable: Bool { get }
|
||||
var session: URLSession { get }
|
||||
}
|
||||
|
||||
|
||||
|
||||
106
KissMe/Sources/Common/WebSocket.swift
Normal file
106
KissMe/Sources/Common/WebSocket.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// WebSocket.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/08/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol WebSocket {
|
||||
associatedtype KResult: Decodable
|
||||
|
||||
var isMockAvailable: Bool { get }
|
||||
var domain: String { get }
|
||||
var url: String { get }
|
||||
var userAgent: String { get }
|
||||
|
||||
var header: [String: String?] { get }
|
||||
var body: [String: Any] { get }
|
||||
var result: KResult? { get set }
|
||||
var timeout: TimeInterval { get }
|
||||
var session: URLSession { get }
|
||||
var socket: URLSessionWebSocketTask? { get set }
|
||||
}
|
||||
|
||||
|
||||
extension WebSocket {
|
||||
public var isMockAvailable: Bool { true }
|
||||
|
||||
public var userAgent: String {
|
||||
//"KissMe/1.0 Matrix/1.0 Golder/1.0"
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
|
||||
}
|
||||
|
||||
public var header: [String: String?] { [:] }
|
||||
public var timeout: TimeInterval { 15 }
|
||||
public var session: URLSession { return URLSession.shared }
|
||||
}
|
||||
|
||||
|
||||
extension WebSocket {
|
||||
|
||||
var queryUrl: URL? {
|
||||
URL(string: domain + url)
|
||||
}
|
||||
|
||||
public mutating func connect() async throws {
|
||||
return try await withUnsafeThrowingContinuation { continuation in
|
||||
|
||||
guard let queryUrl = queryUrl else {
|
||||
continuation.resume(throwing: QueryError.invalidUrl)
|
||||
return
|
||||
}
|
||||
|
||||
socket = session.webSocketTask(with: queryUrl)
|
||||
socket?.resume()
|
||||
|
||||
continuation.resume(returning: ())
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func disconnect() {
|
||||
socket?.cancel(with: .normalClosure, reason: nil)
|
||||
socket = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public protocol AuthWebSocket: WebSocket {
|
||||
var credential: WebSocketCredential { get }
|
||||
}
|
||||
|
||||
|
||||
extension AuthWebSocket {
|
||||
|
||||
// TODO: work later
|
||||
// public var session: URLSession {
|
||||
// }
|
||||
|
||||
public var domain: String {
|
||||
credential.isMock ?
|
||||
"ws://ops.koreainvestment.com:31000":
|
||||
"ws://ops.koreainvestment.com:21000"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public protocol WebSocketCredential {
|
||||
var isMock: Bool { get }
|
||||
var accountNo: String { get }
|
||||
var approvalKey: String { get }
|
||||
}
|
||||
|
||||
|
||||
public struct KissWebSocketCredential: WebSocketCredential, Codable {
|
||||
public let isMock: Bool
|
||||
public let accountNo: String
|
||||
public let approvalKey: String
|
||||
|
||||
public init(isMock: Bool, accountNo: String, approvalKey: String) {
|
||||
self.isMock = isMock
|
||||
self.accountNo = accountNo
|
||||
self.approvalKey = approvalKey
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Do.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/08/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: AskingPriceWebSocket
|
||||
|
||||
extension Domestic {
|
||||
|
||||
/// 국내주식 실시간호가[실시간-004]
|
||||
///
|
||||
public struct AskingPriceWebSocket: AuthWebSocket {
|
||||
public typealias KResult = String
|
||||
|
||||
public var url: String {
|
||||
"/tryitout/H0STASP0"
|
||||
}
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"approval_key": credential.approvalKey,
|
||||
"custtype": "P",
|
||||
"tr_type": "1",
|
||||
"content-type": "utf-8"
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"tr_id": "H0STCNT0",
|
||||
"tr_key": productCode,
|
||||
]
|
||||
}
|
||||
|
||||
public var socket: URLSessionWebSocketTask?
|
||||
public var result: KResult? = nil
|
||||
public var credential: WebSocketCredential
|
||||
var event: Event!
|
||||
let productCode: String
|
||||
|
||||
init(credential: WebSocketCredential, productCode: String) {
|
||||
self.credential = credential
|
||||
self.productCode = productCode
|
||||
self.event = Event(socket: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.AskingPriceWebSocket {
|
||||
|
||||
class Event: NSObject {
|
||||
let socket: Domestic.AskingPriceWebSocket
|
||||
|
||||
init(socket: Domestic.AskingPriceWebSocket) {
|
||||
self.socket = socket
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.AskingPriceWebSocket.Event: URLSessionWebSocketDelegate {
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// DomesticStockRealtime.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/08/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: ContractNoticeWebSocket
|
||||
|
||||
extension Domestic {
|
||||
|
||||
/// 국내주식 실시간체결통보[실시간-005]
|
||||
///
|
||||
public struct ContractNoticeWebSocket: AuthWebSocket {
|
||||
public typealias KResult = String
|
||||
|
||||
public var url: String {
|
||||
"/tryitout/H0STCNI0"
|
||||
}
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"approval_key": credential.approvalKey,
|
||||
"custtype": "P",
|
||||
"tr_type": KissWebSocketSubscription.subscribed.rawValue,
|
||||
"content-type": "utf-8"
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"tr_id": (credential.isMock ? "H0STCNI9": "H0STCNI0"),
|
||||
"tr_key": htsID,
|
||||
]
|
||||
}
|
||||
|
||||
public var socket: URLSessionWebSocketTask?
|
||||
public var result: KResult? = nil
|
||||
public var credential: WebSocketCredential
|
||||
var event: Event!
|
||||
let htsID: String
|
||||
|
||||
init(credential: WebSocketCredential, htsID: String) {
|
||||
self.credential = credential
|
||||
self.htsID = htsID
|
||||
self.event = Event(socket: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.ContractNoticeWebSocket {
|
||||
|
||||
class Event: NSObject {
|
||||
let socket: Domestic.ContractNoticeWebSocket
|
||||
|
||||
init(socket: Domestic.ContractNoticeWebSocket) {
|
||||
self.socket = socket
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.ContractNoticeWebSocket.Event: URLSessionWebSocketDelegate {
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// Domestic.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/08/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
enum KissWebSocketSubscription: String {
|
||||
case subscribed = "1"
|
||||
case unsubscribed = "2"
|
||||
}
|
||||
|
||||
|
||||
protocol KissWebSocketMessage {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: ContractPriceWebSocket
|
||||
|
||||
extension Domestic {
|
||||
|
||||
/// 국내주식 실시간체결가[실시간-003]
|
||||
///
|
||||
public class ContractPriceWebSocket: AuthWebSocket {
|
||||
public typealias KResult = String
|
||||
|
||||
public var url: String {
|
||||
"/tryitout/H0STCNT0"
|
||||
}
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"approval_key": credential.approvalKey,
|
||||
"custtype": "P",
|
||||
"tr_type": KissWebSocketSubscription.subscribed.rawValue,
|
||||
"content-type": "utf-8"
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"tr_id": "H0STASP0",
|
||||
"tr_key": productCode,
|
||||
]
|
||||
}
|
||||
|
||||
public var socket: URLSessionWebSocketTask?
|
||||
public var result: KResult? = nil
|
||||
public var credential: WebSocketCredential
|
||||
var event: Event!
|
||||
let productCode: String
|
||||
|
||||
public init(credential: WebSocketCredential, productCode: String) {
|
||||
self.credential = credential
|
||||
self.productCode = productCode
|
||||
self.event = Event(socket: self)
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Message: KissWebSocketMessage {
|
||||
|
||||
let subscription: KissWebSocketSubscription
|
||||
|
||||
init(subscription: KissWebSocketSubscription) {
|
||||
self.subscription = subscription
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func subscribe() {
|
||||
// json 포맷으로 데이터를 송수신
|
||||
|
||||
}
|
||||
|
||||
func unsubscribe() {
|
||||
// json 포맷으로 데이터를 송수신
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.ContractPriceWebSocket {
|
||||
|
||||
class Event: NSObject {
|
||||
let socket: Domestic.ContractPriceWebSocket
|
||||
|
||||
init(socket: Domestic.ContractPriceWebSocket) {
|
||||
self.socket = socket
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Domestic.ContractPriceWebSocket.Event: URLSessionWebSocketDelegate {
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
|
||||
print("connected...")
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
|
||||
print("disconnected...")
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//
|
||||
// DomesticStockRealtime.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/08/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
extension Domestic {
|
||||
|
||||
}
|
||||
@@ -12,6 +12,10 @@ public class KissAccount: KissProfile {
|
||||
|
||||
let credential: Credential
|
||||
|
||||
public var accountNo: String {
|
||||
credential.accountNo
|
||||
}
|
||||
|
||||
public init(credential: Credential) {
|
||||
self.credential = credential
|
||||
super.init()
|
||||
|
||||
@@ -102,7 +102,7 @@ public struct ApprovalKeyAuthRequest: AuthRequest {
|
||||
[
|
||||
"grant_type": "client_credentials",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret
|
||||
"secretkey": credential.appSecret
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
|
||||
@@ -28,6 +28,9 @@ class KissConsole: KissMe.ShopContext {
|
||||
var indexContext: IndexContext
|
||||
|
||||
let maxCandleDay: Int = 250
|
||||
|
||||
// 005930: 삼성전자
|
||||
static let defaultProductNo: String = "005930"
|
||||
|
||||
|
||||
private enum KissCommand: String {
|
||||
@@ -159,8 +162,7 @@ class KissConsole: KissMe.ShopContext {
|
||||
}
|
||||
semaphore.wait()
|
||||
|
||||
// 005930: 삼성전자
|
||||
setCurrent(productNo: "005930")
|
||||
setCurrent(productNo: KissConsole.defaultProductNo)
|
||||
}
|
||||
|
||||
private func getCommand(_ line: String) -> (KissCommand?, [String]) {
|
||||
|
||||
@@ -7,4 +7,63 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
KissConsole().run()
|
||||
//KissConsole().run()
|
||||
|
||||
import KissMe
|
||||
|
||||
test_get_websocket_key_and_request_simple()
|
||||
|
||||
|
||||
func test_get_websocket_key_and_request_simple() {
|
||||
let isMock = false
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
guard let (account, approvalKey) = await test_get_websocket_key(isMock: isMock) else {
|
||||
return
|
||||
}
|
||||
|
||||
let webSocketCredential = KissWebSocketCredential(isMock: isMock, accountNo: account.accountNo, approvalKey: approvalKey)
|
||||
|
||||
var socket = Domestic.ContractPriceWebSocket(credential: webSocketCredential, productCode: KissConsole.defaultProductNo)
|
||||
|
||||
do {
|
||||
try await socket.connect()
|
||||
try await Task.sleep(nanoseconds: 1_000_000_000 * 3)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
|
||||
|
||||
// 간단한 리퀘스트를 날려보자.
|
||||
// 응답을 체크해서 정리해보자.
|
||||
}
|
||||
|
||||
|
||||
func test_get_websocket_key(isMock: Bool) async -> (KissAccount, String)? {
|
||||
let credential: Credential
|
||||
|
||||
do {
|
||||
credential = try KissCredential(isMock: isMock)
|
||||
} catch {
|
||||
print(error)
|
||||
return nil
|
||||
}
|
||||
|
||||
let account = KissAccount(credential: credential)
|
||||
do {
|
||||
if try await account.login() {
|
||||
let approvalKey = try await account.approvalKey()
|
||||
print("approvalKey : \(approvalKey)")
|
||||
return (account, approvalKey)
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -40,7 +40,10 @@
|
||||
3435A7F72A35D82000D604F1 /* DomesticShortSelling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3435A7F62A35D82000D604F1 /* DomesticShortSelling.swift */; };
|
||||
349C26AB2A1EAE2400F3EC91 /* KissProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */; };
|
||||
349F5D142A6BC8D3009A0526 /* String+Html.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349F5D132A6BC8D3009A0526 /* String+Html.swift */; };
|
||||
34BC44762A8656570052D8EB /* DomesticStockRealtime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BC44752A8656570052D8EB /* DomesticStockRealtime.swift */; };
|
||||
34BC44762A8656570052D8EB /* Domestic.ContractNoticeWebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BC44752A8656570052D8EB /* Domestic.ContractNoticeWebSocket.swift */; };
|
||||
34BC44792A8657D50052D8EB /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BC44782A8657D50052D8EB /* WebSocket.swift */; };
|
||||
34BC447B2A8663430052D8EB /* Domestic.AskingPriceWebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BC447A2A8663430052D8EB /* Domestic.AskingPriceWebSocket.swift */; };
|
||||
34BC447D2A86635A0052D8EB /* Domestic.ContractPriceWebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BC447C2A86635A0052D8EB /* Domestic.ContractPriceWebSocket.swift */; };
|
||||
34C1BA4D2A59CD3400423D64 /* DomesticDartNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C1BA4C2A59CD3400423D64 /* DomesticDartNotice.swift */; };
|
||||
34C1BA4F2A5A603F00423D64 /* DomesticExtra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C1BA4E2A5A603F00423D64 /* DomesticExtra.swift */; };
|
||||
34C1BA512A5A607D00423D64 /* DomesticDart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C1BA502A5A607D00423D64 /* DomesticDart.swift */; };
|
||||
@@ -179,7 +182,10 @@
|
||||
3435A7F62A35D82000D604F1 /* DomesticShortSelling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticShortSelling.swift; sourceTree = "<group>"; };
|
||||
349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissProfile.swift; sourceTree = "<group>"; };
|
||||
349F5D132A6BC8D3009A0526 /* String+Html.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Html.swift"; sourceTree = "<group>"; };
|
||||
34BC44752A8656570052D8EB /* DomesticStockRealtime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockRealtime.swift; sourceTree = "<group>"; };
|
||||
34BC44752A8656570052D8EB /* Domestic.ContractNoticeWebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Domestic.ContractNoticeWebSocket.swift; sourceTree = "<group>"; };
|
||||
34BC44782A8657D50052D8EB /* WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = "<group>"; };
|
||||
34BC447A2A8663430052D8EB /* Domestic.AskingPriceWebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Domestic.AskingPriceWebSocket.swift; sourceTree = "<group>"; };
|
||||
34BC447C2A86635A0052D8EB /* Domestic.ContractPriceWebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Domestic.ContractPriceWebSocket.swift; sourceTree = "<group>"; };
|
||||
34C1BA4C2A59CD3400423D64 /* DomesticDartNotice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticDartNotice.swift; sourceTree = "<group>"; };
|
||||
34C1BA4E2A5A603F00423D64 /* DomesticExtra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticExtra.swift; sourceTree = "<group>"; };
|
||||
34C1BA502A5A607D00423D64 /* DomesticDart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticDart.swift; sourceTree = "<group>"; };
|
||||
@@ -386,6 +392,7 @@
|
||||
341F5F062A14634F00962D48 /* Foundation+Extensions.swift */,
|
||||
34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */,
|
||||
349F5D132A6BC8D3009A0526 /* String+Html.swift */,
|
||||
34BC44782A8657D50052D8EB /* WebSocket.swift */,
|
||||
);
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
@@ -401,7 +408,9 @@
|
||||
34BC44742A8656250052D8EB /* Realtime */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34BC44752A8656570052D8EB /* DomesticStockRealtime.swift */,
|
||||
34BC447C2A86635A0052D8EB /* Domestic.ContractPriceWebSocket.swift */,
|
||||
34BC447A2A8663430052D8EB /* Domestic.AskingPriceWebSocket.swift */,
|
||||
34BC44752A8656570052D8EB /* Domestic.ContractNoticeWebSocket.swift */,
|
||||
);
|
||||
path = Realtime;
|
||||
sourceTree = "<group>";
|
||||
@@ -789,6 +798,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */,
|
||||
34BC447D2A86635A0052D8EB /* Domestic.ContractPriceWebSocket.swift in Sources */,
|
||||
34C1BA882A5D9A4A00423D64 /* DomesticDartDisclosureInterests.swift in Sources */,
|
||||
340A4DC42A4E4345005A1FBA /* ArrayDecodable.swift in Sources */,
|
||||
34C1BA532A5A683D00423D64 /* DomesticDartBusinessReport.swift in Sources */,
|
||||
@@ -801,6 +811,7 @@
|
||||
34C1BA552A5B033E00423D64 /* DomesticDartListedCompany.swift in Sources */,
|
||||
341F5F072A14634F00962D48 /* Foundation+Extensions.swift in Sources */,
|
||||
341F5F032A11A2BC00962D48 /* Credential.swift in Sources */,
|
||||
34BC44792A8657D50052D8EB /* WebSocket.swift in Sources */,
|
||||
341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */,
|
||||
341F5EFD2A10931B00962D48 /* DomesticStockSearch.swift in Sources */,
|
||||
349F5D142A6BC8D3009A0526 /* String+Html.swift in Sources */,
|
||||
@@ -830,9 +841,10 @@
|
||||
341F5EE12A0F373B00962D48 /* Login.swift in Sources */,
|
||||
341F5EF52A0F891200962D48 /* KissAccount.swift in Sources */,
|
||||
340A4DBD2A4C34BE005A1FBA /* IndexContext.swift in Sources */,
|
||||
34BC44762A8656570052D8EB /* DomesticStockRealtime.swift in Sources */,
|
||||
34BC44762A8656570052D8EB /* Domestic.ContractNoticeWebSocket.swift in Sources */,
|
||||
34E7B9112A49BD2800B3AB9F /* DomesticIndex.swift in Sources */,
|
||||
341F5F0D2A15222E00962D48 /* AuthRequest.swift in Sources */,
|
||||
34BC447B2A8663430052D8EB /* Domestic.AskingPriceWebSocket.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user