Administrator
4 days ago 5c29bd9cc72880c9de59e69447e9eeafd53bf633
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.xcong.excoin.modules.gateApi.wsHandler;
 
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.modules.gateApi.GateGridTradeService;
import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
 
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
 
/**
 * 私有频道的抽象基类,封装 HMAC-SHA512 签名和认证请求构建。
 *
 * @author Administrator
 */
@Slf4j
public abstract class AbstractPrivateChannelHandler implements GateChannelHandler {
 
    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
 
    private final String channelName;
    private final String apiKey;
    private final String apiSecret;
    private final String contract;
    private final GateGridTradeService gridTradeService;
 
    public AbstractPrivateChannelHandler(String channelName,
                                          String apiKey, String apiSecret,
                                          String contract,
                                          GateGridTradeService gridTradeService) {
        this.channelName = channelName;
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
        this.contract = contract;
        this.gridTradeService = gridTradeService;
    }
 
    @Override
    public String getChannelName() {
        return channelName;
    }
 
    @Override
    public void subscribe(WebSocketClient ws) {
        long timeSec = System.currentTimeMillis() / 1000;
        JSONObject msg = buildAuthRequest("subscribe", buildUid(), timeSec);
        ws.send(msg.toJSONString());
        log.info("[{}] 已发送订阅请求(含认证),合约: {}", channelName, contract);
    }
 
    @Override
    public void unsubscribe(WebSocketClient ws) {
        JSONObject unsubscribeMsg = new JSONObject();
        unsubscribeMsg.put("time", System.currentTimeMillis() / 1000);
        unsubscribeMsg.put("channel", channelName);
        unsubscribeMsg.put("event", "unsubscribe");
        JSONArray payload = new JSONArray();
        payload.add(contract);
        unsubscribeMsg.put("payload", payload);
        ws.send(unsubscribeMsg.toJSONString());
        log.info("[{}] 已发送取消订阅请求,合约: {}", channelName, contract);
    }
 
    protected GateGridTradeService getGridTradeService() {
        return gridTradeService;
    }
 
    protected String getContract() {
        return contract;
    }
 
    private String buildUid() {
        return gridTradeService != null && gridTradeService.getUserId() != null
                ? String.valueOf(gridTradeService.getUserId()) : "";
    }
 
    private JSONObject buildAuthRequest(String event, String uid, long timeSec) {
        JSONObject msg = new JSONObject();
        msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
        msg.put("time", timeSec);
        msg.put("channel", channelName);
        msg.put("event", event);
        JSONArray payload = new JSONArray();
        payload.add(uid);
        payload.add(contract);
        msg.put("payload", payload);
        JSONObject auth = new JSONObject();
        auth.put("method", "api_key");
        auth.put("KEY", apiKey);
        auth.put("SIGN", hs512Sign(event, timeSec));
        msg.put("auth", auth);
        return msg;
    }
 
    private String hs512Sign(String event, long timeSec) {
        try {
            String message = "channel=" + channelName + "&event=" + event + "&time=" + timeSec;
            Mac mac = Mac.getInstance("HmacSHA512");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
            mac.init(spec);
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            StringBuilder hex = new StringBuilder(hash.length * 2);
            for (byte b : hash) {
                hex.append(HEX_ARRAY[(b >> 4) & 0xF]);
                hex.append(HEX_ARRAY[b & 0xF]);
            }
            return hex.toString();
        } catch (Exception e) {
            log.error("[{}] 签名计算失败", channelName, e);
            return "";
        }
    }
}