Files
KissMe/KissMeConsole/Sources/KissConsole+WebSocket.swift
2023-09-29 20:54:52 +09:00

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
}
}
}