-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
<!-- WARNING: Eclipse auto-generated file. | ||
Any modifications will be overwritten. | ||
To include a user specific buildfile here, simply create one in the same | ||
directory with the processing instruction <?eclipse.ant.import?> | ||
as the first entry and export the buildfile again. --> | ||
<project basedir="." default="build" name="pomelo-androidclient"> | ||
|
||
<property name="target" value="1.6"/> | ||
<property name="source" value="1.6"/> | ||
|
||
<path id="pomelo-androidclient.classpath"> | ||
<pathelement location="bin"/> | ||
<pathelement location="libs/socketio.jar"/> | ||
</path> | ||
|
||
<target name="init"> | ||
<mkdir dir="bin"/> | ||
<copy includeemptydirs="false" todir="bin"> | ||
<fileset dir="src"> | ||
<exclude name="**/*.java"/> | ||
</fileset> | ||
</copy> | ||
</target> | ||
|
||
<target name="clean"> | ||
<delete dir="bin"/> | ||
</target> | ||
|
||
<target depends="init" name="build-project"> | ||
<echo message="${ant.project.name}: ${ant.file}"/> | ||
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}"> | ||
<src path="src"/> | ||
<classpath refid="pomelo-androidclient.classpath"/> | ||
</javac> | ||
</target> | ||
|
||
<target name="jar" depends="build-project"> | ||
<mkdir dir="jar"/> | ||
<jar destfile="jar/pomelo-android-client.jar" basedir="bin"> | ||
<zipgroupfileset dir="libs/" includes="*.jar"/> | ||
<manifest> | ||
</manifest> | ||
</jar> | ||
</target> | ||
</project> |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.netease.pomelo; | ||
|
||
import org.json.JSONObject; | ||
|
||
/** | ||
* Callback function of server response. | ||
* | ||
*/ | ||
public interface DataCallBack { | ||
void responseData(JSONObject message); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.netease.pomelo; | ||
|
||
import java.util.EventObject; | ||
|
||
import org.json.JSONObject; | ||
|
||
/** | ||
* Data event of broadcast message. | ||
* | ||
*/ | ||
public class DataEvent extends EventObject { | ||
|
||
private JSONObject message; | ||
|
||
public JSONObject getMessage() { | ||
return message; | ||
} | ||
|
||
public void setMessage(JSONObject message) { | ||
this.message = message; | ||
} | ||
|
||
public DataEvent(Object source, JSONObject message) { | ||
super(source); | ||
this.message = message; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.netease.pomelo; | ||
|
||
import java.util.EventListener; | ||
|
||
/** | ||
* Listener of broadcast message. | ||
* | ||
*/ | ||
public interface DataListener extends EventListener { | ||
void receiveData(DataEvent event); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
package com.netease.pomelo; | ||
|
||
import java.net.MalformedURLException; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.logging.Logger; | ||
import org.json.JSONArray; | ||
import org.json.JSONException; | ||
import org.json.JSONObject; | ||
import io.socket.IOAcknowledge; | ||
import io.socket.IOCallback; | ||
import io.socket.SocketIO; | ||
import io.socket.SocketIOException; | ||
|
||
public class PomeloClient { | ||
|
||
private static final Logger logger = Logger.getLogger("org.netease.pomelo"); | ||
private final static String URLHEADER = "http://"; | ||
private final static String JSONARRAY_FLAG = "["; | ||
private int reqId; | ||
private PomeloClient client; | ||
private SocketIO socket; | ||
private Map<Integer, DataCallBack> cbs; | ||
private Map<String, List<DataListener>> listeners; | ||
|
||
public PomeloClient(String url, int port) { | ||
initSocket(url, port); | ||
cbs = new HashMap<Integer, DataCallBack>(); | ||
listeners = new HashMap<String, List<DataListener>>(); | ||
} | ||
|
||
/** | ||
* Init the socket of pomelo client. | ||
* | ||
* @param url | ||
* @param port | ||
*/ | ||
private void initSocket(String url, int port) { | ||
StringBuffer buff = new StringBuffer(); | ||
if (!url.contains(URLHEADER)) | ||
buff.append(URLHEADER); | ||
buff.append(url); | ||
buff.append(":"); | ||
buff.append(port); | ||
try { | ||
socket = new SocketIO(buff.toString()); | ||
} catch (MalformedURLException e) { | ||
throw new RuntimeException("please check your url format."); | ||
} | ||
} | ||
|
||
/** | ||
* Connect to the server side and return a pomelo client. | ||
* | ||
* @return client | ||
*/ | ||
public PomeloClient init() { | ||
socket.connect(new IOCallback() { | ||
public void onConnect() { | ||
logger.info("pomeloclient is connected."); | ||
} | ||
|
||
public void onMessage(JSONObject json, IOAcknowledge ack) { | ||
logger.warning("pomelo send message of string."); | ||
} | ||
|
||
// get messages from the server side | ||
public void onMessage(String data, IOAcknowledge ack) { | ||
if (data.indexOf(JSONARRAY_FLAG) == 0) { | ||
processMessageBatch(data); | ||
} else { | ||
processMessage(data); | ||
} | ||
} | ||
|
||
public void onError(SocketIOException socketIOException) { | ||
socketIOException.printStackTrace(); | ||
} | ||
|
||
public void onDisconnect() { | ||
logger.info("connection is terminated."); | ||
socket = null; | ||
} | ||
|
||
public void on(String event, IOAcknowledge ack, Object... args) { | ||
logger.info("socket.io emit events."); | ||
} | ||
|
||
}); | ||
return client; | ||
} | ||
|
||
/** | ||
* Send message to the server side. | ||
* | ||
* @param reqId | ||
* request id | ||
* @param route | ||
* request route | ||
* @param msg | ||
* reqest message | ||
*/ | ||
private void sendMessage(int reqId, String route, JSONObject msg) { | ||
socket.send(Protocol.encode(reqId, route, msg)); | ||
} | ||
|
||
/** | ||
* Client send request to the server and get response data. | ||
* | ||
* @param args | ||
*/ | ||
public void request(Object... args) { | ||
if (args.length < 2 || args.length > 3) { | ||
throw new RuntimeException("the request arguments is error."); | ||
} | ||
// first argument must be string | ||
if (!(args[0] instanceof String)) { | ||
throw new RuntimeException("the route of request is error."); | ||
} | ||
|
||
String route = args[0].toString(); | ||
JSONObject msg = null; | ||
DataCallBack cb = null; | ||
|
||
if (args.length == 2) { | ||
if (args[1] instanceof JSONObject) | ||
msg = (JSONObject) args[1]; | ||
else if (args[1] instanceof DataCallBack) | ||
cb = (DataCallBack) args[1]; | ||
} else { | ||
msg = (JSONObject) args[1]; | ||
cb = (DataCallBack) args[2]; | ||
} | ||
msg = filter(msg); | ||
reqId++; | ||
cbs.put(reqId, cb); | ||
sendMessage(reqId, route, msg); | ||
} | ||
|
||
/** | ||
* Notify the server without response | ||
* | ||
* @param route | ||
* @param msg | ||
*/ | ||
public void inform(String route, JSONObject msg) { | ||
request(route, msg); | ||
} | ||
|
||
/** | ||
* Add timestamp to message. | ||
* | ||
* @param msg | ||
* @return msg | ||
*/ | ||
private JSONObject filter(JSONObject msg) { | ||
if (msg == null) { | ||
msg = new JSONObject(); | ||
} | ||
long date = System.currentTimeMillis(); | ||
try { | ||
msg.put("timestamp", date); | ||
} catch (JSONException e) { | ||
e.printStackTrace(); | ||
} | ||
return msg; | ||
} | ||
|
||
/** | ||
* Disconnect the connection with the server. | ||
*/ | ||
public void disconnect() { | ||
socket.disconnect(); | ||
} | ||
|
||
/** | ||
* Process the message from the server. | ||
* | ||
* @param msg | ||
*/ | ||
private void processMessage(String msg) { | ||
int id; | ||
JSONObject jsonObject = null; | ||
try { | ||
jsonObject = new JSONObject(msg); | ||
// request message | ||
if (jsonObject.has("id")) { | ||
id = jsonObject.getInt("id"); | ||
DataCallBack cb = cbs.get(id); | ||
cb.responseData(jsonObject.getJSONObject("body")); | ||
} | ||
// broadcast message | ||
else { | ||
emit(jsonObject.getString("route"), jsonObject); | ||
} | ||
} catch (JSONException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
/** | ||
* Process message in batch. | ||
* | ||
* @param msgs | ||
*/ | ||
private void processMessageBatch(String msgs) { | ||
JSONArray jsonArray = null; | ||
try { | ||
jsonArray = new JSONArray(msgs); | ||
for (int i = 0; i < jsonArray.length(); i++) { | ||
processMessage(jsonArray.getJSONObject(i).toString()); | ||
} | ||
} catch (JSONException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
/** | ||
* Add event listener and wait for broadcast message. | ||
* | ||
* @param route | ||
* @param listener | ||
*/ | ||
public void on(String route, DataListener listener) { | ||
List<DataListener> list = listeners.get(route); | ||
if (list == null) | ||
list = new ArrayList<DataListener>(); | ||
list.add(listener); | ||
listeners.put(route, list); | ||
} | ||
|
||
/** | ||
* Touch off the event and call listeners corresponding route. | ||
* | ||
* @param route | ||
* @param message | ||
* @return true if call success, false if there is no listeners for this | ||
* route. | ||
*/ | ||
private void emit(String route, JSONObject message) { | ||
List<DataListener> list = listeners.get(route); | ||
if (list == null) { | ||
throw new RuntimeException("there is no listeners."); | ||
} | ||
for (DataListener listener : list) { | ||
DataEvent event = new DataEvent(this, message); | ||
listener.receiveData(event); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.netease.pomelo; | ||
|
||
import org.json.JSONObject; | ||
|
||
public class Protocol { | ||
private final static int HEADER = 5; | ||
|
||
public static String encode(int id, String route, JSONObject msg) { | ||
String str = msg.toString(); | ||
if (route.length() > 255) { | ||
throw new RuntimeException("route max length is overflow."); | ||
} | ||
byte[] arr = new byte[HEADER + route.length()]; | ||
int index = 0; | ||
arr[index++] = (byte) ((id >> 24) & 0xFF); | ||
arr[index++] = (byte) ((id >> 16) & 0xFF); | ||
arr[index++] = (byte) ((id >> 8) & 0xFF); | ||
arr[index++] = (byte) (id & 0xFF); | ||
arr[index++] = (byte) (route.length() & 0xFF); | ||
|
||
for (int i = 0; i < route.length(); i++) { | ||
arr[index++] = (byte) route.codePointAt(i); | ||
} | ||
return bt2Str(arr, 0, arr.length) + str; | ||
} | ||
|
||
private static String bt2Str(byte[] arr, int start, int end) { | ||
StringBuffer buff = new StringBuffer(); | ||
for (int i = start; i < arr.length && i < end; i++) { | ||
buff.append(String.valueOf(Character.toChars(arr[i]))); | ||
} | ||
return buff.toString(); | ||
} | ||
|
||
} |