// Spark IM HTTP + TCP demo against production. // javac docs/clients/SparkImClient.java && java -cp docs/clients SparkImClient import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.URI; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.zip.GZIPInputStream; import javax.net.ssl.SNIHostName; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public final class SparkImClient { static final String API = "https://sparkapi.wyrs365.com"; static final String IM_HOST = "sparkim.wyrs365.com"; static final int IM_PORT = 443; static final int HDR = 23; static final long DEVICE_ID = 7; public static void main(String[] args) throws Exception { String login = httpPost(API + "/v1/auth/login", "{\"email\":\"test01@spark.com\",\"verify_code\":\"000000\",\"device_id\":" + DEVICE_ID + ",\"device_type\":\"android\",\"device_name\":\"demo\"}"); System.out.println("LOGIN " + login); if (!login.contains("\"code\":\"0\"")) { return; } String token = jsonString(login, "access_token"); SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket) factory.createSocket(); SSLParameters params = socket.getSSLParameters(); params.setServerNames(List.of(new SNIHostName(IM_HOST))); socket.setSSLParameters(params); socket.connect(new InetSocketAddress(IM_HOST, IM_PORT), 10_000); socket.startHandshake(); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); DataInputStream in = new DataInputStream(socket.getInputStream()); String auth = "{\"token\":\"" + token + "\",\"device_id\":" + DEVICE_ID + ",\"app_version\":\"1.0.0\",\"language\":\"zh-CN\"}"; write(out, 1, 1, auth); System.out.println("AUTH " + read(in)); write(out, 2, 2, ""); System.out.println("HB " + read(in)); write(out, 4, 3, "{\"peer_id\":1,\"client_msg_id\":\"demo-1\",\"content\":{\"t\":1,\"text\":{\"body\":\"hi\"}}}"); System.out.println("SEND " + read(in)); socket.close(); } static void write(DataOutputStream out, int cmd, int seq, String body) throws IOException { byte[] b = body.getBytes(StandardCharsets.UTF_8); ByteBuffer buf = ByteBuffer.allocate(HDR + b.length); buf.putShort((short) 0x5350).put((byte) 1).putShort((short) cmd).putShort((short) 0) .putLong(0).putInt(seq).putInt(b.length).put(b); out.write(buf.array()); out.flush(); } static String read(DataInputStream in) throws IOException { byte[] h = in.readNBytes(HDR); if (h.length < HDR) { throw new IOException("short header"); } ByteBuffer buf = ByteBuffer.wrap(h); if (buf.getShort() != 0x5350) { throw new IOException("magic"); } buf.get(); int cmd = buf.getShort() & 0xffff; int flags = buf.getShort() & 0xffff; buf.getLong(); int seq = buf.getInt(); int n = buf.getInt(); byte[] body = in.readNBytes(n); if ((flags & 1) != 0) { body = gunzip(body); } return "cmd=" + cmd + " seq=" + seq + " " + new String(body, StandardCharsets.UTF_8); } static byte[] gunzip(byte[] body) throws IOException { try (GZIPInputStream gz = new GZIPInputStream(new ByteArrayInputStream(body)); ByteArrayOutputStream bos = new ByteArrayOutputStream()) { gz.transferTo(bos); return bos.toByteArray(); } } static String httpPost(String url, String json) throws IOException { URL u = URI.create(url).toURL(); HttpURLConnection c = (HttpURLConnection) u.openConnection(); c.setRequestMethod("POST"); c.setDoOutput(true); c.setRequestProperty("Content-Type", "application/json"); c.setRequestProperty("X-Language", "zh-CN"); c.setRequestProperty("X-App-Version", "1.0.0"); try (OutputStream os = c.getOutputStream()) { os.write(json.getBytes(StandardCharsets.UTF_8)); } int code = c.getResponseCode(); InputStream is = code >= 400 ? c.getErrorStream() : c.getInputStream(); try (InputStream in = is) { return new String(in.readAllBytes(), StandardCharsets.UTF_8); } } static String jsonString(String env, String key) { int i = env.indexOf("\"" + key + "\""); int colon = env.indexOf(':', i); int a = env.indexOf('"', colon) + 1; return env.substring(a, env.indexOf('"', a)); } private SparkImClient() {} }