JSON-RPC 2.0 over WebSocket
Realtime API
この接続方法での通信内容は JSON-RPC 2.0 Specification に準拠しています。
エンドポイント
wss://ws.lightstream.bitflyer.com/json-rpc
- JSON-RPC 2.0 にて定められた Batch リクエストをサポートしています。リクエストは配列の先頭から順番に処理されます。
- 接続には TLS 1.2 に対応したクライアントや、場合によっては明示的な設定が必要となります。
サーバーメソッド
auth
- 認証要求をします- params の内容は認証ページを参照してください
- 認証に成功すると true が返ります (必ず確認してください)
subscribe
- チャンネルの購読を開始します- params:
{ channel: "(Channel Name)" }
- 購読が開始されると true が返ります
- params:
unsubscribe
- チャンネルの購読を解除します- params:
{ channel: "(Channel Name)" }
- 購読が解除されると true が返ります
- params:
クライアントメソッド
channelMessage
- 購読している全チャンネルのメッセージが配信されます
利用例
// Node.js (JavaScript)
const crypto = require("crypto");
const RPCClient = require("jsonrpc2-ws").Client;
const key = "{{ YOUR API KEY }}";
const secret = "{{ YOUR API SECRET }}";
const publicChannels = ["lightning_executions_BTC_JPY"];
const privateChannels = ["child_order_events", "parent_order_events"];
const client = new RPCClient("wss://ws.lightstream.bitflyer.com/json-rpc");
// connection handling
client.on("connected", async () => {
// subscribe to the Public Channels
for (const channel of publicChannels) {
try {
await client.call("subscribe", { channel });
} catch (e) {
console.log(channel, "Subscribe Error:", e);
continue;
}
console.log(channel, "Subscribed.");
}
// authentication parameters
const now = Date.now();
const nonce = crypto.randomBytes(16).toString("hex");
const sign = crypto.createHmac("sha256", secret).update(`${now}${nonce}`).digest("hex");
// request auth
try {
await client.call("auth", {
api_key: key,
timestamp: now,
nonce: nonce,
signature: sign
});
} catch (e) {
console.error("auth", "Authentication Error:", e);
return;
}
console.log("auth", "Authenticated.");
// subscribe to the Private Channels
for (const channel of privateChannels) {
try {
await client.call("subscribe", { channel });
} catch (e) {
console.log(channel, "Subscribe Error:", e);
continue;
}
console.log(channel, "Subscribed.");
}
});
// channel messages handling
client.methods.set("channelMessage", (client, notify) => {
console.log("channelMessage", notify.channel, notify.message);
});
// .NET Core / Framework (C# 7.1)
// `dotnet add package StreamJsonRpc -v 1.4.46-beta` or
// `Install-Package -Prerelease StreamJsonRpc`
using Newtonsoft.Json.Linq;
using StreamJsonRpc;
using System;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LightStreamSampleNetCore
{
class Program
{
static async Task Main(string[] args)
{
const string key = "{{ YOUR API KEY }}";
const string secret = "{{ YOUR API SECRET }}";
var publicChannels = new[] { "lightning_executions_BTC_JPY" };
var privateChannels = new[] { "child_order_events", "parent_order_events" };
using (var ws = new ClientWebSocket())
{
await ws.ConnectAsync(new Uri("wss://ws.lightstream.bitflyer.com/json-rpc"), CancellationToken.None);
using (var rpc = new JsonRpc(new WebSocketMessageHandler(ws)))
{
// channel messages handling
rpc.AddLocalRpcMethod("channelMessage", new Action<JToken, CancellationToken>((@params, cancellationToken) =>
{
var p = @params as dynamic;
Console.WriteLine($"{p.channel}: {p.message}");
}));
rpc.StartListening();
// subscribe to the Public Channels
foreach (var channel in publicChannels) {
await rpc.InvokeWithParameterObjectAsync<object>("subscribe", new { channel });
Console.WriteLine($"{channel} Subscribed.");
}
// authentication parameters
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var nonce = Guid.NewGuid().ToString();
var sign = SignWithHMACSHA256($"{now}{nonce}", secret);
// request auth
await rpc.InvokeWithParameterObjectAsync<object>("auth", new {
api_key = key,
timestamp = now,
nonce = nonce,
signature = sign,
});
Console.WriteLine("Authenticated.");
// subscribe to the Private Channels
foreach (var channel in privateChannels) {
await rpc.InvokeWithParameterObjectAsync<object>("subscribe", new { channel });
Console.WriteLine($"{channel} Subscribed.");
}
Console.ReadLine();
}
}
}
static string SignWithHMACSHA256(string data, string secret)
{
using (var encoder = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
{
var hash = encoder.ComputeHash(Encoding.UTF8.GetBytes(data));
return ToHexString(hash);
}
}
static string ToHexString(byte[] bytes)
{
var sb = new StringBuilder(bytes.Length * 2);
foreach (var b in bytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
}
require 'rubygems'
require 'websocket-client-simple'
require 'json'
require 'securerandom'
JSONRPC_ID_AUTH = 1
apiKey = "{{ YOUR API KEY }}"
apiSecret = "{{ YOUR API SECRET }}"
publicChannels = ["lightning_board_snapshot_BTC_JPY"]
privateChannels = ["child_order_events"]
# note: reconnection handling needed for production use.
ws = WebSocket::Client::Simple.connect 'wss://ws.lightstream.bitflyer.com/json-rpc'
ws.on :open do
puts "open"
publicChannels.each do |channel|
json = JSON.generate({:method => :subscribe, :params => { :channel => channel }, :id => nil})
ws.send(json)
end
now = Time.now.strftime('%s%L')
nonce = SecureRandom.hex(16)
sign = OpenSSL::HMAC.hexdigest("sha256", apiSecret, now + nonce)
ws.send(JSON.generate({
:method => :auth,
:params => {
:api_key => apiKey,
:timestamp => now.to_i,
:nonce => nonce,
:signature => sign,
},
:id => JSONRPC_ID_AUTH
}))
end
ws.on :message do |msg|
data = JSON.parse(msg.data)
if data["id"] == JSONRPC_ID_AUTH then
if data["error"] != nil then
puts "auth error: " + data["error"]["message"]
exit
else
puts "authed"
privateChannels.each do |channel|
json = JSON.generate({:method => :subscribe, :params => { :channel => channel }, :id => nil})
ws.send(json)
end
end
end
if data["method"] == "channelMessage" then
p data["params"]
end
end
ws.on :close do |e|
p e
exit 1
end
ws.on :error do |e|
p e
end
print "Please press key to exit."
STDIN.getc
Updated almost 4 years ago