Расширение для Chrome показывает, когда кто-то набирает текст

Некоторые люди слишком много времени проводят в социальных сетях. Настолько много, что у них уже возникает зависимость. Один из таких — программист Александр Кирзенберг (Alexandre Kirszenberg), который к тому же любит копаться во внутренностях Facebook — в коде JavaScript, отвечающем за пользовательский интерфейс и коммуникации.
«Пару месяцев назад я задумался о маленьком статусном индикаторе, который показывает, когда один из ваших друзей набирает вам текст, — пишет Александр. — Такое маленькое расширение UI выдаёт много информации о собеседнике. Если индикатор несколько раз загорается и тухнет, это говорит о нерешительности. Если он загорелся надолго, кто-то пишет вам большое эссе. И нет ничего хуже того мучительного чувства, когда индикатор тухнет и больше не загорается».
Первым делом Александр решил найти, присылает ли Facebook уведомления о том, что кто-то набирает сообщения в Facebook Messenger, даже если у вас не запущен этот Facebook Messenger. Оказалось, что присылает.
Всем друзьям рассылается событие
typ
«длинного опроса» /pull
(long polling). Небольшое исследование показало, что событие действительно рассылается для каждого чата, даже если получатель не открывал его и никогда не получал.Так появилось расширение Facebook Sixth Sense для браузера Chrome. Оно показывает прямо в браузере, когда кто-то набирает сообщение в Facebook.

Для создания этого расширения программист использовал недокументированные Facebook API. Пришлось разбираться с кодом JavaScript, который Facebook безжалостно минифицирует, превращая в мешанину символов.
Сначала он выяснил, какие модули Facebook импортирует через программный интерфейс системы организации модулей Asynchronous Module Definition для асинхронной загрузки (у Facebook собственная реализация AMD). Модули и зависимости определяются стандартной функцией
__d(name, dependencies, factory)
. Есть также require
и requireLazy
для импорта модулей.Проще всего посмотреть, как это работает, в консоли браузера (хотя Facebook строго запрещает это делать). Похоже, там работают серьёзные ребята, с ними лучше не шутить.

Но мы всё-таки осмелимся.

Как видим, Facebook всегда загружает последнюю версию React — отличной библиотеки компонентов пользовательских интерфейсов. Facebook довольно интенсивно использует React по всему сайту. В коде Facebook более 15 000 компонентов React (по состоянию на октябрь 2015 года).
В исходном коде можно поискать
__d(
и посмотреть список модулей, доступных для импорта. Для главной страницы там всего-то 3000 модулей.В чате Facebook Messenger, разумеется, тоже используются компоненты React. Нам нужно перехватить нотификации о наборе текста. Для более детального изучения кода Александр Кирзенберг рекомендует использовать инструмент React Developer Tools.


После установки этого расширения в инструментах разработчика Chrome появляется новая вкладка React. На ней выделяем чат.

Здесь среди различных компонентов Facebook Messenger ищем индикатор набора текста, он находится между
<ChatTabComposerContainer />
и <MercuryLastMessageIndicator />
.Поиск
__d('ChatTyping
в кодовой базе React находит два модуля: ChatTypingIndicator.react.js
и ChatTypingIndicators.react.js
. Это именно то, что нам нужно, пишет Кирзенберг. Он замечает, что некоторые модули подгружаются по мере необходимости, так что ChatTypingIndicators.react.js
можно обнаружить только со второго раза.Вот его код.
function() {
var k = c('MercuryThreadInformer').getForFBID(this.props.viewer)
, l = c('MercuryTypingReceiver').getForFBID(this.props.viewer);
this._subscriptions = new (c('SubscriptionsHandler'))();
this._subscriptions.addSubscriptions(
l.addRetroactiveListener(
'state-changed',
this.typingStateChanged
),
k.subscribe(
'messages-received',
this.messagesReceived
)
);
},
А именно, нас интересует вызов
c('MercuryTypingReceiver')
.В консоли можно посмотреть, как он работает.
> MercuryTypingReceiver.getForFBID
// function (i){var j=this._getInstances();if(!j[i])j[i]=new this(i);return j[i];}
> MercuryTypingReceiver.get
// function (){return this.getForFBID(c('CurrentUser').getID());}
Для проверки, как работает статусный индикатор, Александр использовал приложение Messenger на собственном смартфоне, чтобы отправить себе на ПК соответствующие события и словить их в консоли.
Более подробно изучив код, он нашёл ещё два полезных модуля
MercuryThreads
и ShortProfiles
. Первый получает всю информацию о треде Messenger по его идентификатору, второй делает то же самое по профилю.В общем, после всех изысканий вот как выглядит окончательный код расширения для Chrome, всего 40 строчек.
function getUserId(fbid) {
return fbid.split(':')[1];
}
requireLazy(
['MercuryTypingReceiver', 'MercuryThreads', 'ShortProfiles'],
(MercuryTypingReceiver, MercuryThreads, ShortProfiles) => {
MercuryTypingReceiver
.get()
.addRetroactiveListener('state-changed', onStateChanged);
// Called every time a user starts or stops typing in a thread
function onStateChanged(state) {
// State is a dictionary that maps thread ids to the list of the
// currently typing users ids'
const threadIds = Object.keys(state);
// Walk through all threads in order to retrieve a list of all
// user ids
const userIds = threadIds.reduce(
(res, threadId) => res.concat(state[threadId].map(getUserId)),
[]
);
MercuryThreads.get().getMultiThreadMeta(threadIds, threads => {
ShortProfiles.getMulti(userIds, users => {
// Now that we've retrieved all the information we need
// about the threads and the users, we send it to the
// Chrome application to process and display it to the user.
window.postMessage({
type: 'update',
threads,
users,
state,
}, '*');
});
});
}
}
);
Неплохой такой хак, слегка раскрывающий внутренности Facebook.
Исходный код расширения опубликован на Github.
Кстати, по временным меткам из мессенджера Facebook можно даже отслеживать режим сна своих френдов (исходный код).

Комментарии (22)
TimsTims
03.06.2016 10:15+1Сразу вспомнил, как в QiP была подобная функция уведомления, когда тебе кто-то начинает писать.
Если это был какой-то близкий друг, то я успевал открыть это окно и написать ей(ему) первым: «Привет!»
А она такая: «Ой, привет! ты не поверишь, я только-только хотела тебе написать!»dmitry_ch
03.06.2016 16:32Да-да, первым делом отключал эту фичу и уведомления меня, что мне кто-то пишет. Ну или можно, конечно, смотреть с замиранием, если заняться больше нечем.
Amareis
03.06.2016 10:39+3В Вилларибо только делают расширения, а в Вконтакте уже давно всё встроено )
dmitry_dvm
03.06.2016 10:43+3Для контактика есть расширение, которое во всех диалогах всем друзьям отсылает оповещение о наборе. То есть любой ваш друг, при открытии диалога с вами, видит, что вы набираете текст. Это (по)может свести с ума многих на том конце.
Drim
03.06.2016 10:52Интересное расширение. Может еще кто-то сделает под другие соц. сети (если это возможно конечно)
rodgar
03.06.2016 10:52+3Стилизация текста в консоли:
console.log("%cExtra Large Yellow Text with Red Background", «background: red; color: yellow; font-size: x-large»);
Chrome: developer.chrome.com/devtools/docs/console#styling-console-output-with-css
Firefox: getfirebug.com/wiki/index.php/Console.log
Orky
03.06.2016 10:52+1А я делал примерно такую же приблуду для отслеживания активности друзей и друзей друзей в играх в Стиме.
Можно выявлять забавные паттерны в поведении людей, активности и предпочтениях.
GennPen
03.06.2016 10:52+15пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
«ПРИВЕТ!»Miraage
03.06.2016 17:11+3пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
пользователь набирает сообщение…
)
ivanbolhovitinov
03.06.2016 11:37+4И нет ничего хуже того мучительного чувства, когда индикатор тухнет и больше не загорается
Вот я и сам не знаю, что делатьFen1kz
03.06.2016 13:48+5Всем френдам рассылается событие typ длинного опроса /pull.
Мне кажется, что "френдов" стоило перевести как "друзей", а вот "long polling" наоборот, переводить не стоило, потому что это термин.
handymade
03.06.2016 16:00+1Пришлось разбираться с кодом JavaScript, который Facebook безжалостно минифицирует, превращая в мешанину символов.
годный пятничный пост на хабре
parmactep
03.06.2016 23:06+1Очевидно фейсбук не запрещает рыться в консоли. Фейсбук предупреждает. Думается это правильно с их стороны.
acupofspirt
Для такой «слежки» и Большой брат не нужен