265 lines
8.3 KiB
Swift
265 lines
8.3 KiB
Swift
//
|
|
// KissConsole+WebSocket.swift
|
|
// KissMeConsole
|
|
//
|
|
// Created by ened-book-m1 on 2023/09/04.
|
|
//
|
|
|
|
import Foundation
|
|
import KissMe
|
|
|
|
|
|
extension KissConsole {
|
|
}
|
|
|
|
|
|
public protocol KissAuctionPriceDelegate: AnyObject {
|
|
func auction(_ auction: KissAuction, contactPrice: Domestic.ContractPrice)
|
|
func auction(_ auction: KissAuction, askingPrice: Domestic.AskingPrice)
|
|
}
|
|
|
|
|
|
public protocol KissAutionNoticeDelegate: AnyObject {
|
|
func auction(_ auction: KissAuction, contactNotice: Domestic.ContractNotice)
|
|
}
|
|
|
|
|
|
public class KissAuction: NSObject {
|
|
|
|
public class Slot {
|
|
var contractPrice: Domestic.ContractPriceWebSocket!
|
|
var askingPrice: Domestic.AskingPriceWebSocket!
|
|
weak var delegate: KissAuctionPriceDelegate?
|
|
|
|
var contractPriceReceiver: ContractPriceReceiver!
|
|
var askingPriceReceiver: AskingPriceReceiver!
|
|
|
|
init(delegate: KissAuctionPriceDelegate?) {
|
|
self.delegate = delegate
|
|
}
|
|
|
|
func setup(contractPrice: Domestic.ContractPriceWebSocket, askingPrice: Domestic.AskingPriceWebSocket) {
|
|
self.contractPrice = contractPrice
|
|
self.askingPrice = askingPrice
|
|
}
|
|
|
|
func cleanup() {
|
|
contractPriceReceiver.slot = nil
|
|
contractPriceReceiver.owner = nil
|
|
askingPriceReceiver.slot = nil
|
|
askingPriceReceiver.owner = nil
|
|
}
|
|
}
|
|
|
|
class ContractPriceReceiver {
|
|
var slot: Slot?
|
|
weak var owner: KissAuction?
|
|
|
|
init(slot: Slot?, owner: KissAuction) {
|
|
self.slot = slot
|
|
self.owner = owner
|
|
}
|
|
}
|
|
|
|
class AskingPriceReceiver {
|
|
var slot: Slot?
|
|
weak var owner: KissAuction?
|
|
|
|
init(slot: Slot?, owner: KissAuction) {
|
|
self.slot = slot
|
|
self.owner = owner
|
|
}
|
|
}
|
|
|
|
class ContractNoticeReceiver {
|
|
weak var delegate: KissAutionNoticeDelegate?
|
|
weak var owner: KissAuction?
|
|
|
|
init(delegate: KissAutionNoticeDelegate?, owner: KissAuction) {
|
|
self.delegate = delegate
|
|
self.owner = owner
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: ensure thread-safe
|
|
var slots: [Slot]
|
|
|
|
let loggable: Bool
|
|
let account: KissAccount
|
|
var contractNotice: Domestic.ContractNoticeWebSocket?
|
|
var contractNoticeReceiver: ContractNoticeReceiver?
|
|
|
|
public init(account: KissAccount, loggable: Bool) {
|
|
self.slots = [Slot]()
|
|
self.loggable = loggable
|
|
self.account = account
|
|
self.contractNotice = nil
|
|
self.contractNoticeReceiver = nil
|
|
}
|
|
|
|
|
|
public func startNotice(delegate: KissAutionNoticeDelegate?) async throws -> Bool {
|
|
//account.approvalKeys.
|
|
guard let isMock = account.isMock else {
|
|
throw GeneralError.invalidAccessToken
|
|
}
|
|
let approvalKey = try await account.getApprovalKey()
|
|
print("notice price key: \(approvalKey)")
|
|
let credential = KissWebSocketCredential(isMock: isMock, accountNo: account.accountNo, approvalKey: approvalKey)
|
|
|
|
contractNotice = Domestic.ContractNoticeWebSocket(credential: credential, htsID: account.accountNo)
|
|
contractNoticeReceiver = ContractNoticeReceiver(delegate: delegate, owner: self)
|
|
|
|
try await contractNotice!.connect()
|
|
let result = try await contractNotice!.subscribe()
|
|
return result
|
|
}
|
|
|
|
|
|
public func stopNotice() async throws -> Bool {
|
|
guard var contractNotice = contractNotice else {
|
|
return false
|
|
}
|
|
|
|
let result = try await contractNotice.unsubscribe()
|
|
contractNotice.disconnect()
|
|
contractNoticeReceiver?.delegate = nil
|
|
return result
|
|
}
|
|
|
|
|
|
public func addSlot(productNo: String, delegate: KissAuctionPriceDelegate?) async throws -> Slot {
|
|
guard let isMock = account.isMock else {
|
|
throw GeneralError.invalidAccessToken
|
|
}
|
|
|
|
func createContractPrice() async throws -> Domestic.ContractPriceWebSocket {
|
|
let approvalKey = try await account.getApprovalKey()
|
|
print("contract price key: \(approvalKey)")
|
|
let credential = KissWebSocketCredential(isMock: isMock, accountNo: account.accountNo, approvalKey: approvalKey)
|
|
|
|
let contractPrice = Domestic.ContractPriceWebSocket(credential: credential, productCode: productNo)
|
|
return contractPrice
|
|
}
|
|
|
|
func createAskingPrice() async throws -> Domestic.AskingPriceWebSocket {
|
|
let approvalKey = try await account.getApprovalKey()
|
|
print("asking price key: \(approvalKey)")
|
|
let credential = KissWebSocketCredential(isMock: isMock, accountNo: account.accountNo, approvalKey: approvalKey)
|
|
|
|
let askingPrice = Domestic.AskingPriceWebSocket(credential: credential, productCode: productNo)
|
|
return askingPrice
|
|
}
|
|
|
|
let slot = Slot(delegate: delegate)
|
|
slot.askingPriceReceiver = AskingPriceReceiver(slot: slot, owner: self)
|
|
slot.contractPriceReceiver = ContractPriceReceiver(slot: slot, owner: self)
|
|
|
|
var contractPrice = try await createContractPrice()
|
|
try await contractPrice.connect()
|
|
let result = try await contractPrice.subscribe()
|
|
guard result else {
|
|
throw GeneralError.cannotSubscribeWebSocket
|
|
}
|
|
|
|
var askingPrice = try await createAskingPrice()
|
|
try await askingPrice.connect()
|
|
let result2 = try await askingPrice.subscribe()
|
|
guard result2 else {
|
|
throw GeneralError.cannotSubscribeWebSocket
|
|
}
|
|
|
|
slot.setup(contractPrice: contractPrice, askingPrice: askingPrice)
|
|
slots.append(slot)
|
|
return slot
|
|
}
|
|
|
|
|
|
public func getSlot(productNo: String) -> Slot? {
|
|
guard let slot = slots.first(where: { $0.contractPrice.productCode == productNo }) else {
|
|
return nil
|
|
}
|
|
return slot
|
|
}
|
|
|
|
|
|
public func removeSlot(productNo: String) async throws -> Bool {
|
|
guard let slotIndex = slots.firstIndex(where: { $0.contractPrice.productCode == productNo }) else {
|
|
return false
|
|
}
|
|
let slot = slots.remove(at: slotIndex)
|
|
slot.cleanup()
|
|
return true
|
|
}
|
|
|
|
private func getWebSocketKey() async throws -> KissWebSocketCredential {
|
|
guard let isMock = account.isMock else {
|
|
throw GeneralError.invalidAccessToken
|
|
}
|
|
|
|
if try await account.login() {
|
|
let approvalKey = try await account.getApprovalKey()
|
|
return KissWebSocketCredential(isMock: isMock, accountNo: account.accountNo, approvalKey: approvalKey)
|
|
}
|
|
throw GeneralError.cannotIssueApprovalKey
|
|
}
|
|
}
|
|
|
|
|
|
extension KissAuction.ContractPriceReceiver: WebSocketDelegate {
|
|
|
|
func webSocket(_ webSocket: WebSocket, didPingpong dateTime: String) {
|
|
}
|
|
|
|
func webSocket(_ webSocket: WebSocket, didReceive data: Any) {
|
|
guard let owner = owner else { return }
|
|
guard let data = data as? Domestic.WebSocketData else { return }
|
|
|
|
switch data {
|
|
case .contractPrice(let price):
|
|
slot?.delegate?.auction(owner, contactPrice: price)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension KissAuction.AskingPriceReceiver: WebSocketDelegate {
|
|
|
|
func webSocket(_ webSocket: WebSocket, didPingpong dateTime: String) {
|
|
}
|
|
|
|
func webSocket(_ webSocket: WebSocket, didReceive data: Any) {
|
|
guard let owner = owner else { return }
|
|
guard let data = data as? Domestic.WebSocketData else { return }
|
|
|
|
switch data {
|
|
case .askingPrice(let price):
|
|
slot?.delegate?.auction(owner, askingPrice: price)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension KissAuction.ContractNoticeReceiver: WebSocketDelegate {
|
|
|
|
func webSocket(_ webSocket: WebSocket, didPingpong dateTime: String) {
|
|
}
|
|
|
|
func webSocket(_ webSocket: WebSocket, didReceive data: Any) {
|
|
guard let owner = owner else { return }
|
|
guard let data = data as? Domestic.WebSocketData else { return }
|
|
|
|
switch data {
|
|
case .contractNotice(let notice):
|
|
delegate?.auction(owner, contactNotice: notice)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|