@BPI @TangZhiLong Find the equivalent codes for swift and elastOS
Besides adding friends and sending simple messages, carrier also provides a mechanism of session to help transferring large files, of stream raw data.
Please note that transferring files can be implemented in an easier way than what is described here. Using sessions and streams is the generic way, but for convenience, consider using the FileTransfer class for simple file transfers.
Streams described here are the lower level layer. They can be considered as the physical communication layer. You can also create channels in order to push different kind of information (ex: send 2 files simultaneously) inside the same stream.
Here is how 2 peers can setup a data flow together:
Session manager uses a handler class to receive new session requests:
ManagerHandler mSessionManagerHandler = new ManagerHandler() {
@Override
public void onSessionRequest(Carrier carrier, String fromUserId, String sdp) {
// A new session request is received from a friend peer.
// ... Code to handle this request goes here. See below in this guide.
}
}
declare let carrierPlugin: any;
let callbacks = {
onSessionRequest: session_request_callback,
}
function session_request_callback(event) {
// do something
}
Session manager is initialized using the session manager handler created earlier.
Manager.initializeInstance(Carrier.getInstance(), mSessionManagerHandler);
Manager manager = Manager.getInstance();
declare let carrierPlugin: any;
let carrierInst;
let sessionInst;
function carrierSuccess(ret) {
carrierInst = ret;
}
function carrierError(ret) {
// do something
}
function sessionSuccess(ret) {
sessionInst = ret;
}
function sessionError(ret) {
// do something
}
carrierPlugin.createObject(carrierSuccess, carrierError, null, callbacks);
carrierInst.newSession(sessionSuccess, sessionError, peerId);
All callbacks related to a carrier session need a handler class implementation. It looks like this:
AbstractStreamHandler streamHandler = new AbstractStreamHandler {
@Override
public void onStateChanged(Stream stream, StreamState streamState) {
// Stream state changes arrive here
}
@Override
public void onStreamData(Stream stream, byte[] data) {
// Data received from a peer
}
@Override
public void onChannelOpened(Stream stream, int channel) {
}
@Override
public void onChannelClose(Stream stream, int channel, CloseReason reason) {
}
@Override
public boolean onChannelData(Stream stream, int channel, byte[] data) {
return false;
}
}
}
let stream_callbacks = {
onStateChanged: state_changed_callback,
onStreamData: stream_data_callback,
onChannelOpen: channel_open_callback,
onChannelOpened: channel_opened_callback,
onChannelClose: channel_close_callback,
onChannelData: channel_data_callback,
onChannelPending: channel_pending_callback,
onChannelResume: channel_resume_callback,
}
function state_changed_callback(event) {
// do something
}
function stream_data_callback(event) {
// do something
}
function channel_open_callback(event) {
// do something
}
function channel_opened_callback(event) {
// do something
}
function channel_close_callback(event) {
// do something
}
function channel_data_callback(event) {
// do something
}
function channel_pending_callback(event) {
// do something
}
function channel_resume_callback(event) {
// do something
}
SessionRequestCompleteHandler sessionHandler = new SessionRequestCompleteHandler {
public void onCompletion(Session session, int state, String reason, String sdp) {
// This is called when peer 1 gets session reply from peer 2
}
}
function session_request_complete_callback(event) {
// do something
}
function success(ret) {
// do something
}
function error(ret) {
// do something
}
sessionInst.request(success, error, session_request_complete_callback);
A new session is created locally. One or several streams are configured (added) in this session.
// Use a peer address to create a new session
Session session = carrierSessionManager.newSession(peerAddr);
// Add a stream to the session. For example, a video session
Stream stream = session.addStream(StreamType.Application, 0, streamHandler);
// Optionally: create more streams and add them. Some stream can be reliable (similar to tcp - no data lost but uses more bandwidth - good for file transfer). By default, streams are unreliable (similar to udp - good for video streaming) a reliable session (for file transfer or data that can't be lost - similar to TCP)
Stream mySecondStream = session.addStream(StreamType.Text, Stream.PROPERTY_RELIABLE, streamHandler);
let sessionInst;
let stream;
function success(ret) {
sessionInst = ret;
}
function error(ret) {
// do something
}
function streamSuccess(ret) {
stream = ret;
}
function streamError(ret) {
// do something
}
carrierInst.newSession(success, error, peerId);
sessionInst.addStream(streamSuccess, streamError, TEXT, PLAIN, stream_callbacks);
After session and streams are created, the whole information has to be sent to carrier to let the friend peer know about this initialization.
But here comes a bit of complication: before sending the actual session request, you need to make sure that all the streams you have added have moved to state Initialized. Choose your preferred way to do so using any code synchzoniration mechanism.
// Request actual session creation to carrier
session.request(sessionHandler);
sessionInst.request(success, error, session_request_complete_callback);
Peer 2 will then be notified that a new session is being created by peer 1 inside its ManagerHandler, onSessionRequest(). At that time, peer 2 can do the same as peer 1 in order to create a local session and add streams into it.
Session session = carrierSessionManager.newSession(peerAddr);
Stream stream = session.addStream(StreamType.Application, 0, streamHandler);
let sessionInst;
let stream;
function success(ret) {
sessionInst = ret;
}
function error(ret) {
// do something
}
function streamSuccess(ret) {
stream = ret;
}
function streamError(ret) {
// do something
}
carrierInst.newSession(success, error, peerId);
sessionInst.addStream(streamSuccess, streamError, TEXT, PLAIN, stream_callbacks);
Again, we need to wait until all streams reach the TransportReady state here before sending the following response to peer 1:
session.replyRequest(0, null); // Success
session.start(sdp); // sdp is provided in onSessionRequest()
function replySuccess(ret) {
// do something
}
function replyError(ret) {
// do something
}
function startSuccess(ret) {
// do something
}
function startError(ret) {
// do something
}
sessionInst.replyRequest(replySuccess, replyError, 0, "success");
sessionInst.start(startSuccess, startError, sdp);
Peer 1 is currently waiting for peer 2, and will be notified in onCompletion() when peer 2 replied to the session request.
before starting its session, peer 1 needs to wait for 2 conditions:
When those conditions are met, the following code can be called:
session.start(sdp); // sdp is provided in onCompletion()
sessionInst.start(startSuccess, startError, sdp);
Now it’s almost ready. Your stream handler will receive onStateChanged() with state Connected. At that time, you can start sending data with the following code:
int sentSize = stream.writeData(data);
function writeSuccess(ret) {
// do something
}
function writeError(ret) {
// do something
}
stream.write(writeSuccess, writeError, data);
or
stream.write(writeSuccess, writeError, channel, data);
Peer 2 is now able to receive data from stream handler’s onStreamData().