Rocket.Chat.ReactNative/app/lib/rocketchat.js

446 lines
12 KiB
JavaScript
Raw Normal View History

2017-08-09 20:18:00 +00:00
import Meteor from 'react-native-meteor';
import Random from 'react-native-meteor/lib/Random';
2017-11-18 20:17:24 +00:00
import { AsyncStorage, Platform } from 'react-native';
import { hashPassword } from 'react-native-meteor/lib/utils';
2017-08-13 01:35:09 +00:00
import RNFetchBlob from 'react-native-fetch-blob';
import reduxStore from './createStore';
import settingsType from '../constants/settings';
2017-08-09 20:18:00 +00:00
import realm from './realm';
import * as actions from '../actions';
2017-11-20 22:18:00 +00:00
import { typing } from '../actions/room';
2017-08-17 16:55:47 +00:00
import { disconnect, connectSuccess } from '../actions/connect';
2017-08-09 20:18:00 +00:00
export { Accounts } from 'react-native-meteor';
2017-08-11 18:18:09 +00:00
const call = (method, ...params) => new Promise((resolve, reject) => {
Meteor.call(method, ...params, (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
});
const TOKEN_KEY = 'reactnativemeteor_usertoken';
2017-08-11 18:18:09 +00:00
2017-08-13 01:35:09 +00:00
const RocketChat = {
TOKEN_KEY,
createChannel({ name, users, type }) {
2017-11-19 02:31:34 +00:00
return call(type ? 'createChannel' : 'createPrivateGroup', name, users, type);
},
2017-08-13 01:35:09 +00:00
async getUserToken() {
try {
return await AsyncStorage.getItem(TOKEN_KEY);
} catch (error) {
console.warn(`AsyncStorage error: ${ error.message }`);
}
},
async testServer(url) {
if (/^(https?:\/\/)?(((\w|[0-9])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
const response = await fetch(url, { method: 'HEAD' });
if (response.status === 200 && response.headers.get('x-instance-id') != null && response.headers.get('x-instance-id').length) {
return url;
}
}
throw new Error({ error: 'invalid server' });
},
connect(_url) {
return new Promise((resolve) => {
const url = `${ _url }/websocket`;
2017-08-09 20:18:00 +00:00
2017-08-17 16:55:47 +00:00
Meteor.connect(url, { autoConnect: true, autoReconnect: true });
2017-11-19 02:44:55 +00:00
2017-08-17 16:55:47 +00:00
Meteor.ddp.on('disconnected', () => {
reduxStore.dispatch(disconnect());
});
2017-11-19 02:44:55 +00:00
Meteor.ddp.on('connected', () => {
2017-08-17 20:15:24 +00:00
reduxStore.dispatch(connectSuccess());
resolve();
2017-08-09 20:18:00 +00:00
});
2017-08-17 16:55:47 +00:00
2017-11-19 02:44:55 +00:00
Meteor.ddp.on('connected', async() => {
2017-11-20 22:18:00 +00:00
Meteor.ddp.on('changed', (ddpMessage) => {
2017-11-21 00:52:48 +00:00
const server = { id: reduxStore.getState().server.server };
2017-11-20 22:18:00 +00:00
if (ddpMessage.collection === 'stream-room-messages') {
2017-11-21 16:55:32 +00:00
return realm.write(() => {
2017-11-20 22:18:00 +00:00
const message = ddpMessage.fields.args[0];
2017-08-17 16:55:47 +00:00
message.temp = false;
2017-11-21 00:52:48 +00:00
message._server = server;
2017-11-21 00:58:15 +00:00
message.attachments = message.attachments || [];
2017-08-17 16:55:47 +00:00
realm.create('messages', message, true);
});
}
2017-11-20 22:18:00 +00:00
if (ddpMessage.collection === 'stream-notify-room') {
const [_rid, ev] = ddpMessage.fields.eventName.split('/');
if (ev !== 'typing') {
return;
}
2017-11-21 16:55:32 +00:00
return reduxStore.dispatch(typing({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
2017-11-20 22:18:00 +00:00
}
if (ddpMessage.collection === 'stream-notify-user') {
2017-11-21 13:17:54 +00:00
const [type, data] = ddpMessage.fields.args;
const [, ev] = ddpMessage.fields.eventName.split('/');
2017-11-21 00:52:48 +00:00
if (/subscriptions/.test(ev)) {
switch (type) {
case 'inserted':
data._server = server;
realm.write(() => {
realm.create('subscriptions', data, true);
});
break;
case 'updated':
delete data._updatedAt;
realm.write(() => {
realm.create('subscriptions', data, true);
});
break;
default:
}
}
if (/rooms/.test(ev) && type === 'updated') {
const sub = realm.objects('subscriptions').filtered('rid == $0', data._id)[0];
realm.write(() => {
sub._updatedAt = data._updatedAt;
});
}
2017-08-17 16:55:47 +00:00
}
});
2017-11-19 02:44:55 +00:00
RocketChat.getSettings();
2017-08-09 20:18:00 +00:00
});
})
.catch(e => console.error(e));
2017-08-09 20:18:00 +00:00
},
2017-08-17 16:55:47 +00:00
login(params, callback) {
return new Promise((resolve, reject) => {
2017-08-16 23:29:12 +00:00
Meteor._startLoggingIn();
2017-08-17 01:09:44 +00:00
return Meteor.call('login', params, (err, result) => {
2017-08-16 23:29:12 +00:00
Meteor._endLoggingIn();
Meteor._handleLoginCallback(err, result);
if (err) {
2017-11-20 17:27:34 +00:00
if (/user not found/i.test(err.reason)) {
err.error = 1;
err.reason = 'User or Password incorrect';
err.message = 'User or Password incorrect';
}
reject(err);
} else {
resolve(result);
}
2017-08-16 23:29:12 +00:00
if (typeof callback === 'function') {
callback(err, result);
}
});
});
},
me({ server, token, userId }) {
return fetch(`${ server }/api/v1/me`, {
method: 'get',
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': token,
'X-User-Id': userId
}
}).then(response => response.json());
},
register({ credentials }) {
2017-11-19 02:31:34 +00:00
return call('registerUser', credentials);
},
setUsername({ credentials }) {
2017-11-19 02:31:34 +00:00
return call('setUsername', credentials.username);
},
forgotPassword(email) {
2017-11-19 02:31:34 +00:00
return call('sendForgotPasswordEmail', email);
},
2017-08-14 14:15:37 +00:00
loginWithPassword({ username, password, code }, callback) {
let params = {};
const state = reduxStore.getState();
if (state.settings.LDAP_Enable) {
params = {
ldap: true,
username,
ldapPass: password,
ldapOptions: {}
};
} else if (state.settings.CROWD_Enable) {
params = {
crowd: true,
username,
crowdPassword: password
};
} else {
params = {
password: hashPassword(password),
user: {
username
}
};
2017-08-17 01:09:44 +00:00
if (typeof username === 'string' && username.indexOf('@') !== -1) {
params.user = { email: username };
}
}
2017-08-14 00:31:22 +00:00
if (code) {
params = {
totp: {
login: params,
code
}
};
}
2017-08-16 23:29:12 +00:00
return this.login(params, callback);
2017-08-09 20:18:00 +00:00
},
loadSubscriptions(cb) {
Meteor.call('subscriptions/get', (err, data) => {
if (err) {
console.error(err);
}
2017-08-11 18:18:09 +00:00
if (data.length) {
realm.write(() => {
data.forEach((subscription) => {
// const subscription = {
// _id: item._id
// };
// if (typeof item.value === 'string') {
// subscription.value = item.value;
// }
subscription._server = { id: reduxStore.getState().server.server };
2017-08-14 18:02:53 +00:00
// write('subscriptions', subscription);
2017-08-11 18:18:09 +00:00
realm.create('subscriptions', subscription, true);
});
2017-08-09 20:18:00 +00:00
});
2017-08-11 18:18:09 +00:00
}
2017-08-09 20:18:00 +00:00
return cb && cb();
});
},
2017-11-18 20:17:24 +00:00
registerPushToken(id, token) {
const key = Platform.OS === 'ios' ? 'apn' : 'gcm';
const data = {
id: `RocketChatRN${ id }`,
token: { [key]: token },
appName: 'main',
userId: id,
metadata: {}
};
return call('raix:push-update', data);
},
updatePushToken(pushId) {
return call('raix:push-setuser', pushId);
},
2017-08-09 20:18:00 +00:00
2017-08-10 23:21:46 +00:00
loadMessagesForRoom(rid, end, cb) {
2017-08-17 06:28:41 +00:00
return new Promise((resolve, reject) => {
Meteor.call('loadHistory', rid, end, 20, (err, data) => {
if (err) {
if (cb) {
cb({ end: true });
}
return reject(err);
2017-08-10 23:21:46 +00:00
}
2017-08-17 20:15:24 +00:00
if (data && data.messages.length) {
2017-08-17 06:28:41 +00:00
realm.write(() => {
data.messages.forEach((message) => {
message.temp = false;
message._server = { id: reduxStore.getState().server.server };
2017-11-21 00:58:15 +00:00
message.attachments = message.attachments || [];
2017-08-17 06:28:41 +00:00
// write('messages', message);
realm.create('messages', message, true);
});
2017-08-11 18:18:09 +00:00
});
2017-08-17 06:28:41 +00:00
}
2017-08-09 20:18:00 +00:00
2017-08-17 06:28:41 +00:00
if (cb) {
2017-08-17 20:15:24 +00:00
if (data && data.messages.length < 20) {
2017-08-17 06:28:41 +00:00
cb({ end: true });
} else {
cb({ end: false });
}
2017-08-10 23:21:46 +00:00
}
2017-08-17 06:28:41 +00:00
resolve();
});
2017-08-09 20:18:00 +00:00
});
},
getMessage(rid, msg = {}) {
2017-08-09 20:18:00 +00:00
const _id = Random.id();
2017-08-21 00:11:46 +00:00
// console.log('reduxStore.getState().login.id ', reduxStore.getState().login);
const message = {
_id,
rid,
msg,
ts: new Date(),
_updatedAt: new Date(),
temp: true,
_server: { id: reduxStore.getState().server.server },
u: {
2017-08-21 00:11:46 +00:00
_id: reduxStore.getState().login.user.id || '1',
2017-11-13 22:49:52 +00:00
username: reduxStore.getState().login.user.username
}
};
2017-08-09 20:18:00 +00:00
realm.write(() => {
realm.create('messages', message, true);
// write('messages', message, true);
2017-08-09 20:18:00 +00:00
});
return message;
},
sendMessage(rid, msg) {
const tempMessage = this.getMessage(rid, msg);
return call('sendMessage', { _id: tempMessage._id, rid, msg });
2017-08-10 16:16:32 +00:00
},
spotlight(search, usernames) {
2017-11-19 02:31:34 +00:00
return call('spotlight', search, usernames);
2017-08-10 16:16:32 +00:00
},
createDirectMessage(username) {
2017-11-19 02:31:34 +00:00
return call('createDirectMessage', username);
2017-08-10 16:16:32 +00:00
},
2017-08-11 18:18:09 +00:00
readMessages(rid) {
return call('readMessages', rid);
},
2017-08-10 16:16:32 +00:00
joinRoom(rid) {
2017-11-19 02:31:34 +00:00
return call('joinRoom', rid);
2017-08-10 20:09:54 +00:00
},
/*
"name":"yXfExLErmNR5eNPx7.png"
"size":961
"type":"image/png"
"rid":"GENERAL"
"description":""
"store":"fileSystem"
*/
_ufsCreate(fileInfo) {
// return call('ufsCreate', fileInfo);
2017-11-19 02:31:34 +00:00
return call('ufsCreate', fileInfo);
2017-08-10 20:09:54 +00:00
},
// ["ZTE8CKHJt7LATv7Me","fileSystem","e8E96b2819"
_ufsComplete(fileId, store, token) {
2017-11-19 02:31:34 +00:00
return call('ufsComplete', fileId, store, token);
2017-08-10 20:09:54 +00:00
},
/*
- "GENERAL"
- {
"type":"image/png",
"size":961,
"name":"yXfExLErmNR5eNPx7.png",
"description":"",
"url":"/ufs/fileSystem/ZTE8CKHJt7LATv7Me/yXfExLErmNR5eNPx7.png"
}
*/
_sendFileMessage(rid, data, msg = {}) {
2017-11-19 02:31:34 +00:00
return call('sendFileMessage', rid, null, data, msg);
2017-08-14 14:25:17 +00:00
},
async sendFileMessage(rid, fileInfo, data) {
const placeholder = RocketChat.getMessage(rid, 'Sending an image');
try {
const result = await RocketChat._ufsCreate({ ...fileInfo, rid });
await RNFetchBlob.fetch('POST', result.url, {
'Content-Type': 'application/octet-stream'
}, data);
const completeRresult = await RocketChat._ufsComplete(result.fileId, fileInfo.store, result.token);
return await RocketChat._sendFileMessage(completeRresult.rid, {
_id: completeRresult._id,
type: completeRresult.type,
size: completeRresult.size,
name: completeRresult.name,
url: completeRresult.path
});
} catch (e) {
return e;
} finally {
realm.write(() => {
const msg = realm.objects('messages').filtered('_id = $0', placeholder._id);
realm.delete(msg);
});
}
},
2017-11-19 04:09:56 +00:00
async getRooms() {
const { server, login } = reduxStore.getState();
let lastMessage = realm
.objects('subscriptions')
.filtered('_server.id = $0', server.server)
.sorted('_updatedAt', true)[0];
lastMessage = lastMessage && new Date(lastMessage._updatedAt);
let [subscriptions, rooms] = await Promise.all([call('subscriptions/get', lastMessage), call('rooms/get', lastMessage)]);
if (lastMessage) {
subscriptions = subscriptions.update;
rooms = rooms.update;
}
const data = subscriptions.map((subscription) => {
const room = rooms.find(({ _id }) => _id === subscription.rid);
delete subscription._updatedAt;
if (room) {
subscription._updatedAt = room._updatedAt;
}
2017-11-19 04:09:56 +00:00
subscription._server = { id: server.server };
return subscription;
});
2017-11-19 04:09:56 +00:00
realm.write(() => {
data.forEach(subscription =>
realm.create('subscriptions', subscription, true));
});
2017-11-19 04:09:56 +00:00
Meteor.subscribe('stream-notify-user', `${ login.user.id }/subscriptions-changed`, false);
2017-11-21 00:52:48 +00:00
Meteor.subscribe('stream-notify-user', `${ login.user.id }/rooms-changed`, false);
2017-11-19 04:09:56 +00:00
return data;
2017-08-17 02:06:22 +00:00
},
logout({ server }) {
Meteor.logout();
Meteor.disconnect();
AsyncStorage.removeItem(TOKEN_KEY);
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
2017-11-19 02:44:55 +00:00
},
async getSettings() {
const temp = realm.objects('settings').sorted('_updatedAt', true)[0];
const result = await (!temp ? call('public-settings/get') : call('public-settings/get', new Date(temp._updatedAt)));
const settings = temp ? result.update : result;
const filteredSettings = RocketChat._prepareSettings(RocketChat._filterSettings(settings));
2017-11-19 02:44:55 +00:00
realm.write(() => {
filteredSettings.forEach(setting => realm.create('settings', setting, true));
});
reduxStore.dispatch(actions.setAllSettings(RocketChat.parseSettings(filteredSettings)));
},
parseSettings: settings => settings.reduce((ret, item) => {
ret[item._id] = item[settingsType[item.type]] || item.valueAsString || item.value;
2017-11-19 02:44:55 +00:00
return ret;
}, {}),
_prepareSettings(settings) {
return settings.map((setting) => {
setting[settingsType[setting.type]] = setting.value;
return setting;
});
},
2017-11-20 22:18:00 +00:00
_filterSettings: settings => settings.filter(setting => settingsType[setting.type] && setting.value),
subscribe(...args) {
return Meteor.subscribe(...args);
},
2017-11-21 16:55:32 +00:00
emitTyping(room, t = true) {
const { login } = reduxStore.getState();
return call('stream-notify-room', `${ room }/typing`, login.user.username, t);
2017-11-20 22:18:00 +00:00
}
2017-08-09 20:18:00 +00:00
};
export default RocketChat;