mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-13 18:45:49 +05:00
240 lines
6.8 KiB
JavaScript
240 lines
6.8 KiB
JavaScript
const m = require('mithril');
|
|
|
|
const API_URL = 'http://127.0.0.1:9092';
|
|
let loginKey = {
|
|
username: '',
|
|
passwd: '',
|
|
isVerified: false,
|
|
url: API_URL
|
|
};
|
|
|
|
// Make this as object property?
|
|
function setKeys(username, password, url = API_URL, verified = true) {
|
|
loginKey.username = username;
|
|
loginKey.passwd = password;
|
|
loginKey.url = url;
|
|
loginKey.isVerified = verified;
|
|
}
|
|
|
|
function rsJsonApiRequest(
|
|
path,
|
|
data = {},
|
|
callback = () => {},
|
|
async = true,
|
|
headers = {},
|
|
handleDeserialize = JSON.parse,
|
|
handleSerialize = JSON.stringify,
|
|
config = null
|
|
) {
|
|
headers['Accept'] = 'application/json';
|
|
if (loginKey.isVerified) {
|
|
headers['Authorization'] =
|
|
'Basic ' + btoa(loginKey.username + ':' + loginKey.passwd);
|
|
}
|
|
// NOTE: After upgrading to mithrilv2, options.extract is no longer required
|
|
// since the status will become part of return value and then
|
|
// handleDeserialize can also be simply passed as options.deserialize
|
|
return m
|
|
.request({
|
|
method: 'POST',
|
|
url: loginKey.url + path,
|
|
async,
|
|
extract: xhr => {
|
|
// Empty string is not valid json and fails on parse
|
|
let response = xhr.responseText || '""';
|
|
return {
|
|
status: xhr.status,
|
|
statusText: xhr.statusText,
|
|
body: handleDeserialize(response)
|
|
};
|
|
},
|
|
serialize: handleSerialize,
|
|
headers: headers,
|
|
body: data,
|
|
config: config
|
|
})
|
|
.then(result => {
|
|
if (result.status === 200) {
|
|
callback(result.body, true);
|
|
} else {
|
|
loginKey.isVerified = false;
|
|
callback(result, false);
|
|
m.route.set('/');
|
|
}
|
|
return result;
|
|
})
|
|
.catch(function(e) {
|
|
callback(e, false);
|
|
console.error(
|
|
'Error: While sending request for path:',
|
|
path,
|
|
'\ninfo:',
|
|
e
|
|
);
|
|
m.route.set('/');
|
|
});
|
|
}
|
|
|
|
function setBackgroundTask(task, interval, taskInScope) {
|
|
// Always use bound(.bind) function when accsssing outside objects
|
|
// to avoid loss of scope
|
|
task();
|
|
let taskId = setTimeout(function caller() {
|
|
if (taskInScope()) {
|
|
task();
|
|
taskId = setTimeout(caller, interval);
|
|
} else {
|
|
clearTimeout(taskId);
|
|
}
|
|
}, interval);
|
|
return taskId;
|
|
}
|
|
|
|
function computeIfMissing(map, key, missing = () => ({})) {
|
|
if (!map.hasOwnProperty(key)) {
|
|
map[key] = missing();
|
|
}
|
|
return map[key];
|
|
}
|
|
|
|
function deeperIfExist(map, key, action) {
|
|
if (map.hasOwnProperty(key)) {
|
|
action(map[key]);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const eventQueue = {
|
|
events: {
|
|
15: { // Chat-Messages
|
|
types: {
|
|
// #define RS_CHAT_TYPE_PUBLIC 1
|
|
// #define RS_CHAT_TYPE_PRIVATE 2
|
|
2: chat_id => chat_id.distant_chat_id, // distant chat (initiate? -> todo accept)
|
|
// #define RS_CHAT_TYPE_LOBBY 3
|
|
3: chat_id => chat_id.lobby_id.xstr64, // lobby_id
|
|
// #define RS_CHAT_TYPE_DISTANT 4
|
|
},
|
|
messages: {},
|
|
chatMessages: (chat_id, owner, action) => {
|
|
if (!deeperIfExist(
|
|
owner.types,
|
|
chat_id.type,
|
|
keyfn => action(computeIfMissing(computeIfMissing(owner.messages,chat_id.type), keyfn(chat_id),()=>[]))
|
|
)) {
|
|
console.info('unknown chat event', chat_id);
|
|
};
|
|
},
|
|
handler: (event,owner) => owner.chatMessages(event.mChatMessage.chat_id, owner, r => {
|
|
console.info('adding chat' ,r , event.mChatMessage);
|
|
r.push(event.mChatMessage);
|
|
owner.notify(event.mChatMessage);
|
|
}),
|
|
notify: () => {},
|
|
},
|
|
8: { // Circles (ignore in the meantime)
|
|
handler: (event,owner) => {},
|
|
}
|
|
},
|
|
handler: event => {
|
|
if (!deeperIfExist(eventQueue.events, event.mType, owner => owner.handler(event, owner))) {
|
|
console.info('unhandled event', event);
|
|
};
|
|
},
|
|
}
|
|
|
|
const userList = {
|
|
users: [],
|
|
userMap: {},
|
|
loadUsers: () => {
|
|
rsJsonApiRequest('/rsIdentity/getIdentitiesSummaries', {},
|
|
list=> {
|
|
if (list!== undefined) {
|
|
console.info('loading ' + list.ids.length + ' users ...');
|
|
userList.users=list.ids;
|
|
userList.userMap = list.ids.reduce((a,c) => {
|
|
a[c.mGroupId] = c.mGroupName;
|
|
return a;
|
|
}, {});
|
|
}
|
|
}
|
|
);
|
|
},
|
|
username: id => {
|
|
return userList.userMap[id]||id;
|
|
},
|
|
}
|
|
|
|
/*
|
|
path,
|
|
data = {},
|
|
callback = () => {},
|
|
async = true,
|
|
headers = {},
|
|
handleDeserialize = JSON.parse,
|
|
handleSerialize = JSON.stringify
|
|
config
|
|
*/
|
|
function startEventQueue(info, loginHeader = {}, displayAuthError = () => {}, displayErrorMessage = () => {}, successful = () => {}){
|
|
return rsJsonApiRequest('/rsEvents/registerEventsHandler', {},
|
|
(data, success) => {
|
|
if (success) {
|
|
// unused
|
|
} else if (data.status == 401) {
|
|
displayAuthError('Incorrect login/password.');
|
|
} else if (data.status == 0) {
|
|
displayErrorMessage(['Retroshare-jsonapi not available.',m('br'),'Please fix host and/or port.']);
|
|
} else {
|
|
displayErrorMessage('Login failed: HTTP ' + data.status + ' ' + data.statusText);
|
|
}
|
|
},
|
|
true, loginHeader, JSON.parse, JSON.stringify,
|
|
(xhr, args, url) => {
|
|
let lastIndex = 0;
|
|
xhr.onprogress = ev => {
|
|
let currIndex = xhr.responseText.length;
|
|
if (currIndex > lastIndex) {
|
|
let parts = xhr.responseText.substring(lastIndex,currIndex);
|
|
lastIndex=currIndex;
|
|
for(data of parts.trim().split('\n\n').filter(e=> e.startsWith('data: {')).map(e=> e.substr(6)).map(JSON.parse)){
|
|
if (data.hasOwnProperty('retval')) {
|
|
console.info(info + ' [' + data.retval.errorCategory + '] ' + data.retval.errorMessage);
|
|
if (data.retval.errorNumber === 0) {
|
|
successful();
|
|
} else {
|
|
displayErrorMessage(info + ' failed: [' + data.retval.errorCategory + '] ' + data.retval.errorMessage);
|
|
}
|
|
} else if(data.hasOwnProperty('event')) {
|
|
data.event.queueSize = currIndex;
|
|
eventQueue.handler(data.event);
|
|
}
|
|
}
|
|
if (currIndex > 1e5) { // max 100 kB eventQueue
|
|
startEventQueue('restart queue');
|
|
xhr.abort();
|
|
}
|
|
}
|
|
}
|
|
return xhr;
|
|
}
|
|
);
|
|
}
|
|
|
|
function logon(loginHeader, displayAuthError, displayErrorMessage, successful){
|
|
startEventQueue('login', loginHeader, displayAuthError, displayErrorMessage, () => {
|
|
successful();
|
|
userList.loadUsers();
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
rsJsonApiRequest,
|
|
setKeys,
|
|
setBackgroundTask,
|
|
logon,
|
|
events: eventQueue.events,
|
|
userList,
|
|
};
|