let m = require('mithril');
let rs = require('rswebui');
let people_util = require('people/people_util');
// **************** utility functions ********************
function loadLobbyDetails(id, apply) {
rs.rsJsonApiRequest('/rsMsgs/getChatLobbyInfo', {
id,
},
detail => {
if (detail.retval) {
apply(detail.info);
}
},
true, {},
undefined,
// Custom serializer NOTE:
// Since id represents 64-bit int(see deserializer note below)
// Instead of using JSON.stringify, this function directly
// creates a json string manually.
() => '{"id":' + id + '}')
}
function sortLobbies(lobbies){
if (lobbies !== undefined){
let list= [...lobbies];
list.sort((a,b) => a.lobby_name.localeCompare(b.lobby_name));
return list;
}
// return lobbies; // fallback on reload page in browser, keep undefiend
}
// ***************************** models ***********************************
let ChatRoomsModel = {
allRooms: [],
knownSubscrIds:[], // to exclude subscribed from public rooms (subscribedRooms filled to late)
subscribedRooms: {},
loadPublicRooms() {
// TODO: this doesn't preserve id of rooms,
// use regex on response to extract ids.
rs.rsJsonApiRequest('/rsMsgs/getListOfNearbyChatLobbies', {},
data => ChatRoomsModel.allRooms = sortLobbies(data.public_lobbies),
);
},
loadSubscribedRooms(after = null) {
// ChatRoomsModel.subscribedRooms = {};
rs.rsJsonApiRequest('/rsMsgs/getChatLobbyList', {},
// JS uses double precision numbers of 64 bit. It is equivalent
// to 53 bits of precision. All large precision ints will
// get truncated to an approximation.
// This API uses Cpp-style 64 bits for `id`.
// So we use the string-value 'xstr64' instead
data => {
let ids = data.cl_list.map(lid => lid.xstr64);
ChatRoomsModel.knownSubscrIds = ids;
let rooms = {};
ids.map(id => loadLobbyDetails(id, info => {
rooms[id]= info;
if (Object.keys(rooms).length===ids.length) {
// apply rooms to subscribedRooms only after reading all room-details, so sorting all or nothing
ChatRoomsModel.subscribedRooms = rooms;
}
}));
if (after != null) {
after()
}
},
)
},
subscribed(info) {
return this.knownSubscrIds.includes(info.lobby_id.xstr64);
},
};
const ChatLobbyModel = {
currentLobby: {
lobby_name: '...',
},
lobby_user: '...',
isSubscribed: false,
messages: [],
users: [],
setupAction: (lobby_id, nick) => {},
setIdentity(lobby_id, nick) {
rs.rsJsonApiRequest(
'/rsMsgs/setIdentityForChatLobby',
{},
() => m.route.set('/chat/:lobby_id',{lobby_id: lobby_id}),
true,
{},
JSON.parse,
()=> '{"lobby_id":' + lobby_id + ',"nick":"' + nick + '"}'
);
},
enterPublicLobby(lobby_id, nick) {
console.info('joinVisibleChatLobby', nick, '@', lobby_id)
rs.rsJsonApiRequest(
'/rsMsgs/joinVisibleChatLobby',
{},
() => {
loadLobbyDetails(lobby_id, info => {
ChatRoomsModel.subscribedRooms[lobby_id]= info;
ChatRoomsModel.loadSubscribedRooms(() => {
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
})
});
},
true,
{},
JSON.parse,
()=> '{"lobby_id":' + lobby_id + ',"own_id":"' + nick + '"}'
);
},
unsubscribeChatLobby(lobby_id, follow) {
console.info('unsubscribe lobby', lobby_id)
rs.rsJsonApiRequest(
'/rsMsgs/unsubscribeChatLobby',
{},
() => ChatRoomsModel.loadSubscribedRooms(follow),
true,
{},
JSON.parse,
() => '{"lobby_id":' + lobby_id + '}'
)
},
chatId(action) {
return {type:3,lobby_id:{xstr64:m.route.param('lobby')}};
},
loadLobby (currentlobbyid) {
loadLobbyDetails(currentlobbyid, detail => {
this.setupAction= this.setIdentity;
this.currentLobby = detail;
this.isSubscribed = true;
this.lobby_user = rs.userList.username(detail.gxs_id) || '???';
let lobbyid = currentlobbyid;
// apply existing messages to current lobby view
rs.events[15].chatMessages(this.chatId(),rs.events[15], l => (this.messages = l.map(msg=> m(Message, msg))));
// register for chatEvents for future messages
rs.events[15].notify = chatMessage => {
if (chatMessage.chat_id.type===3 && chatMessage.chat_id.lobby_id.xstr64 === lobbyid) {
this.messages.push(m(Message,chatMessage));
m.redraw();
}
}
// lookup for chat-user names (only snapshot, we don't get notified about changes of participants)
var names = detail.gxs_ids.reduce((a,u) => a.concat(rs.userList.username(u.key)), []);
names.sort((a,b) => a.localeCompare(b));
this.users = [];
names.forEach(name => this.users = this.users.concat([m('.user',name)]));
return this.users;
});
},
loadPublicLobby (currentlobbyid) {
console.info('loadPublicLobby ChatRoomsModel:',ChatRoomsModel);
this.setupAction= this.enterPublicLobby;
this.isSubscribed = false;
ChatRoomsModel.allRooms.forEach(it => {
if (it.lobby_id.xstr64 === currentlobbyid) {
this.currentLobby = it;
this.lobby_user = '???';
this.lobbyid = currentlobbyid;
}
})
this.users = []
},
sendMessage(msg, onsuccess) {
rs.rsJsonApiRequest('/rsmsgs/sendChat', {},
() => {
// adding own message to log
rs.events[15].handler({
mChatMessage:{
chat_id:this.chatId(),
msg:msg,
sendTime:new Date().getTime()/1000,
lobby_peer_gxs_id:this.currentLobby.gxs_id,
}
},rs.events[15]);
onsuccess();
},
true, {}, undefined,
() => '{"id":{"type": 3,"lobby_id":' + m.route.param('lobby') + '}, "msg":' + JSON.stringify(msg) + '}'
);
},
selected(info, selName, defaultName) {
let currid = (ChatLobbyModel.currentLobby.lobby_id || {xstr64: m.route.param('lobby')}).xstr64
return ((info.lobby_id.xstr64 === currid) ? selName : '') + defaultName;
},
switchToEvent(info) {
return () => {
ChatLobbyModel.currentLobby = info;
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
ChatLobbyModel.loadLobby(info.lobby_id.xstr64); // update
};
},
setupEvent(info) {
return () => {
m.route.set('/chat/:lobby/setup', { lobby: info.lobby_id.xstr64 });
ChatLobbyModel.loadPublicLobby(info.lobby_id.xstr64); // update
};
}
}
// ************************* views ****************************
/**
* Message displays a single Chat-Message
* currently removes formatting and in consequence inline links
* msg: Message to Display
*/
const Message = () => {
let msg = null; // message to display
let text = ''; // extracted text to display
let datetime = ''; // date time to display
let username = ''; // username to display (later may be linked)
return {
oninit: vnode => {
console.info('chat Message',vnode);
msg = vnode.attrs;
datetime = new Date(msg.sendTime * 1000).toLocaleTimeString();
username = rs.userList.username(msg.lobby_peer_gxs_id);
text = msg.msg.replaceAll('
','\n').replace(new RegExp('