kabuステーションAPI(REST API)をmac上で動かしてみる

## モチベ
windowsライセンス無い & linuxで動かしている先駆者がいたため
先駆者様: https://minokamo.tokyo/2022/01/31/4383/

環境: MacBookPro(intel) Ventura
(wine crossoverがM1に対応しているっぽいのでM1でも動くかも)

## kabuステーションを動かす

### homebrew wine crossoverのインストール

```
$ brew install --cask --no-quarantine gcenx/wine/wine-crossover
$ brew install winetricks
```

### winetricksからdotnet48をインストール
```
$ winetricks
# 「Select the default wineprefix」 > 「Install a Windows DLL or compornent」 > 「dotnet48」
# 再起動するかを聞かれたら成功
# (.NET4、.NET4.8のインストールはよく失敗します。その都度、~/.wineを削除して再度挑戦してください)
```

---

自分の環境下では.NET4インストール後、下のエラーで4.8のインストールに進まず。。。
```
Unsupported Windows version winxp64
```
正しい対処法なのかは不明だが、wineticksを書き換えて無理やりwin7互換でインストール

---

### kabuステーションのインストール & 起動

```
$ wine rundll32 dfshim.dll,ShOpenVerbApplication http://download.r10.kabu.co.jp/kabustation/KabuStation.application
# ここで下のようなエラーが出る場合はwine prefix(~/.wine)を削除し再度dotnet48のインストール
## module:import_dll Library mscoree.dll (which is needed by L"C:\\windows\\system32\\dfshim.dll") not found
## err:rundll32:wWinMain Unable to find the entry point L"ShOpenVerbApplication" in L"dfshim.dll"
```

crossover22.1.1だとkabuステーション自体は動くがAPIが起動できない。。。


## kabuステーションAPIを動かす

### 問題の原因

1. HttpAddUrl(http.sys/httpapi.dll)にURLのパスを含む場合リクエストがタイムアウトする
(wine8では修正済み(https://github.com/wine-mirror/wine/commit/296852b2585576dfe523f4217becb4cd6101035d))
2. websocket.dllがstub状態であるため、System.Net.Websocketsで例外が発生する
```
00:00:00.0000,E,0032,0009 リクエスト処理中のエラー
System.TypeInitializationException: The type initializer for 'System.Net.WebSockets.WebSocketProtocolComponent' threw an exception. ---> System.Runtime.InteropServices.SEHExcep
tion: External component has thrown an exception.
   at System.Net.WebSockets.WebSocketProtocolComponent.WebSocketCreateClientHandle_Raw(Property[] properties, UInt32 propertyCount, SafeWebSocketHandle& webSocketHandle)
   at System.Net.WebSockets.WebSocketProtocolComponent.GetSupportedVersion()
   at System.Net.WebSockets.WebSocketProtocolComponent..cctor()
   --- End of inner exception stack trace ---
   at System.Net.HttpListenerRequest.get_IsWebSocketRequest()
   at ub.a(HttpListenerContext A_0)
```

### http.sys & httpapiの修正

wineからソースコードを取ってきて上書き

```
$ for filename in "Makefile.in" "request.h" "http.c";do
    curl "https://raw.githubusercontent.com/wine-mirror/wine/0ba9567a5651418b2f373643e70895fc2de6d9fc/dlls/http.sys/$filename" >"sources/wine/dlls/http.sys/$filename"
done
$ curl "https://raw.githubusercontent.com/wine-mirror/wine/master/dlls/httpapi/httpapi_main.c" >sources/wine/dlls/httpapi/httpapi_main.c
```

### wine crossoverのビルド

ビルド補助のスクリプトを使ってビルドしていきます。
参考: https://qiita.com/asfdrwe/items/4ec23b00dfb3272e26a1

```
$ git clone https://github.com/GabLeRoux/macos-crossover-wine-cloud-builder.git
$ cd macos-crossover-wine-cloud-builder/
$ sh local_build.sh
# 自分の環境下ではdxvkとwineのopenalのビルドで失敗
# dxvkはコメントアウト
# openalはwineのconfigureのオプションに--without-openalをつけ回避
```

### websocket.dllの問題の回避

websocketは諦めて、`~/.wine/drive_c/windows/system32/websocket.dll`を削除
(https://github.com/microsoft/referencesource/blob/51cf7850defa8a17d815b4700b67116e3fa283c2/System/net/System/Net/WebSockets/WebSocketProtocolComponent.cs#LL360C17-L360C17 がinvalidになるように)
誰か実装してください🙇

### kabuステーションのインストール & API
```
$ ./install/wine-cx22.1.1/usr/local/bin/wine64 rundll32,...(上と同じ)
# API設定などをしたあとに
$ curl -X POST "http://localhost:18080/kabusapi/token" -H 'Content-Type: application/json' -d '{"APIPassword":"<設定したパスワード>"}'
{"ResultCode":0,"Token":"00000000000000000000000000000000"}
$ curl -H "X-API-KEY: 00000000000000000000000000000000" "http://localhost:18080/kabusapi/symbol/5713@1" | jq
{
  "DisplayName": "住友鉱",
  "Exchange": 1,
  "ExchangeName": "東証プ",
  "UpperLimit": 5439,
  "LowerLimit": 4039,
  "Symbol": "5713",
  "SymbolName": "住友金属鉱山",
  ...
}
```


## まとめ
初めてwineを触った所感としては仮想マシンとかparallelsを使った方がコスパ良い。
問題が発生をしたらtraceを眺めるのを10時間以上繰り返してた。
でも、CTFみたいな楽しみがあったのでヨシ。