Chat Samples

Chat API? – Chat as a distributed sandbox!

APlay Service Storm allows to build arbitrary distributed systems.
The following chat example is built leveraging Service Storm primitives and as such can be extended or completely changed according to your needs.
You could decide to wrap low level Service Storm calls in a higher level API, or stay most flexible and stick with Service Storm API.

Sending and receiving chat messages

Chat Client:

var json = JObject();
  json["message"] = "Hello World";
  _storm.Path("/chat/room[1]/chatMessage").SendMessage(json);

Logging Service:

_storm.Path("/chat/room[*]/chatMessage").OnMessage((json, path, endpointInfo)=>
  {
    // handle messages from ALL chatrooms.
  });

 

Joining / creating a specific chat room and receiving messages

Chat Client:

private void RegisterHandlers(){
  _storm.PathCollection("/chat/room/").OnIntroduce((roomPath, json, sessionObject) =>
  {
    roomPath.Path("chatMessage").OnMessage((json, path, endpointInfo) =>
    {
      // receive massages inside of this room.
    });
  });
}
private void JoinRoom(String roomName){
  var json = new JObject();
  json["room"]= roomName;

  _storm.Path("/chat/joinRoom/")
    .SendRequest(json, (apJson, path, info) =>
    {
      // handle server response if you like
    });
}

Chat Control Service:

private void RegisterHandlers(){
  // Handle Join Room requests
  _storm.Path("/chat/joinRoom").OnRequest(OnJoinRequest);

}
private void OnJoinRequest(JObject requestJson, IAPResponder responder, IAPPath path, IEndpointObject sessionObject){
  var roomData = new JObject();
  roomData["name"] = requestJson["name"];

  // find or create a room that has the given properties.
  _storm.PathCollection("/chat/room/").GetOrCreateChild(roomData, (room, newlyCreated) =>
  {
    sessionObject.Introduce(room); // introduce room to client session
  });
}

 

Validation

Chat Client:

var json = JObject();
  json["message"] = "Hello BAD World";
  _storm.Path("/chat/room[1]/chatMessage").SendMessage(json);

Validation Service:

_storm.Path("/chat/room[*]/chatMessage").OnValidateMessage((json, path, responder, endpointInfo)=>
  {
    String valueBefore = json["message"];
    String correctedValue = valueBefore.Replace("BAD","...");

    if(valueBefore != correctedValue){
      json["message"] = correctedValue;

      // the validation corrected something, correct it.
      // Note: responder.Correct, Accept and Reject are AStorm features.
      responder.Correct(json);
    }else{
      responder.Accept();
    }
  });

 

Login / SSO

Chat Client:

var loginDataJson = JObject();
  loginDataJson["name"] = "myUsername";
  loginDataJson["token"] = "SSOtoken by gamserver!?";

  _storm.Path("/login").SendRequest(loginDataJson, (json, path, sessionObject) =>
  {
    // json contains answer from auth server and decides if logged in.

  });

Auth Service (very simple):

_storm.Path("/login").OnRequest((json, responder, path, sessionObject) =>
  {
    if (true) { // check login is fine.
      // set result json for login allowed
      responder.Respond(resultJson);
    } else {
      // set result json for login not allowed.
      responder.Respond(resultJson);
    }
  });

Auth Service:

_storm.Path("/login").OnRequest((json, responder, path, sessionObject) =>
{
  var resultJson = JObject();
  if (IsSSOLoginAllowed(json)) { // check login is fine.
    var publicChatterInfo = new JObject();
    publicChatterInfo["name"] = json[name];
    publicChatterInfo["color"] = GetRandomColor();
    sessionObject.SetData(json); // set public client data

    // (... later explained: setup roles)

    resultJson["loggedIn"] = true;
    responder.Respond(resultJson);
  } else {
    resultJson["loggedIn"] = false;
    responder.Respond(resultJson);
  }
});

Whisper

Chat Client:

public void onConnect(IEndpointObject thisSession)
{
  thisSession.Path("whisper").onMessage(json, path, chatterSession)=>{
    // received whisper by chatterSession.name
  });
}
public void SendWhisperTo(IEndpointObject chatterSession,JObject json){
  chatterSession.SendMessage(msg,json);
}

 

Whisper via chatrom

Chat Client:

var otherChatter = JObject();
otherChatter["whisperTarget"] = chatterAddress;

_connector.Path("/chat/requestWhisper").SendRequest(otherChatter);

Chat Control Service:

_connector.Path("/chat/requestWhisper").onRequest(OnRequestWhisper);
private void OnRequestWhisper(JObject json, IAPResponder responder, IAPPath path, IEndpointObject endpoint)
{
  var whisperTarget = json["whisperTarget"];
  var address = endpoint.GetTargetAddress();
  var roomName = GetWhisperKey(whisperTarget, address);
  var roomData = new JObject();
  roomData["name"] = roomName;
  _connector.PathCollection("/chat/room/").GetOrCreateChild(roomData, (room, newlyCreated) =>
  {
    _connector.IntroduceObjectToEndpoint(whisperTarget, room);
    _connector.IntroduceObjectToEndpoint(address, room);
  });
}

 

Role Assignment

Endpoint (Client or Service):

_storm.SetConnectionRole("ChatServer");

Auth Service (inside if-block when login is ok):

_storm.Path("/login").OnRequest((json, responder, path, sessionObject) =>{
  if (IsSSOLoginAllowed(json)) { // check login is fine.
    // (...)

    sessionObject.AddRole("/","chatter");
    if(IsModerator(json)){
      sessionObject.AddRole("/","moderator");
    }

    // (...)
  }
});

Chat Control Service:

// (...) Inside of join room call

  if(IsModeratorForRoom(room,sessionObject)){
    sessionObject.AddRole(room,"moderator");
  }

 

Role Based Distribution: Only moderators may kick players

Done on any service:

_storm.Setup('/chat/room/[*]/kick')
.Distribution({
  'default':{
    send: false,
    receive: false
  },
  'Moderator':{
    send: true          // moderator can send kick
  },
  'ChatServer':{
    receive: true       // chat server can receive kick
  },
});

Client:

roomPath.Path("kick").SendMessage({user: userSessionId});

ChatServer:

_storm.Path('/chat/room/[*]/kick').OnMessage((...) => {
  // do real kick logic
});

 

Role Based Distribution: Validation is required for chatters

Done on any service:

_storm.Setup('/chat/room/[*]/chatMessage')
.Distribution({
  'default':{
    send: true,
    receive: true,
    validationRequired : true      // it is required to validate this message
  },
  'Moderator':{
    validationRequired : false     // moderator can write whatever he wants
  },
  'ChatServer':{
    canValidate : true        	   // chat server can validate this path
  },
});

 

Role Based Distribution – defaults

Done on any service:

_storm.Setup('/').Distribution({
  'default':{
    send: false,
    receive: false,
    connectionTimeout: true      				  // drop connection after a time if not logged in!
  },
  'Chatter':{
    send:true,
    receive:true,
    sendLimit:{messageAmount: 10, timeFrame: 60}  // chatter can only send 10 messages every 60 seconds.
  },
  'Moderator':{
    send:true,
    receive:true
  },
  'ChatServer':{
    send:true,
    receive:true
  },
});

 

Role Setup

Done on any service:

_storm.CreateOrUpdateRole('default',
    {
                                           // possible to define default values for all roles
  });
_storm.CreateOrUpdateRole('Chatter',
  {
    devSetup: []                       // no setup allowed
  });
_storm.CreateOrUpdateRole('Moderator',
  {
    devSetup: []                       // no setup allowed
    allowedAtConnection: false         // it is not possible to request this role when connecting
  });
_storm.CreateOrUpdateRole('ChatServer',
  {
    devSetup: ['roles','distribution'] // allowed to setup roles and distribution in dev mode
    allowedIps: ['169.168.0.*',...],   // role only allowed for ips
    allowedInterfaces: [...]           // role only allowed for interfaces
    allowRoleAssignment: true          // this role can assign roles to endpoints
  });