Підміна дати в застосунку на Electron
Пошукайте це, і кожна відповідь буде про зміну власного коду: замокати об’єкт
Date, використати фальшиві таймери вашого тестового фреймворку. Ніщо з цього не
допомагає, коли у вас готовий зібраний застосунок. Ця програма запускає той застосунок, який у вас
уже є.
Чому впровадження до нього не сягає
Цей режим існує через конкретну невдачу. Таймер Pomodoro на Electron запустили в сесії
x60, і його зворотний відлік узагалі не зрушив. Розбір пакета застосунку
показав дві незалежні причини, і жодна не мала розв’язання на нативному боці:
- Зворотний відлік не читав годинник. Це був лічильник, що збільшується
setInterval, який працював усередині Web Worker. Перехоплювати було нічого: виклику часу немає, бо застосунок ніколи не питав, котра година. - Цей worker живе в ізольованому процесі рендерера, тобто саме там, куди бібліотека, впроваджена ззовні, не потрапляє.
Тож механізм на боці Windows тут не допоможе, а відповідь — звертатися натомість до власного рушія JavaScript застосунку.
Що відбувається натомість
Застосунок запускається з портом налагодження й чистим одноразовим профілем, а його власні API
часу переводяться на годинник сесії через протокол DevTools — Date.now, конструктор
new Date(), performance.now, setTimeout і
setInterval.
Підміна встановлюється в кожен контекст, який відкриває застосунок, зокрема в його Web Worker — саме там зазвичай і опиняється таймер, і це єдине місце, куди нативне впровадження ніколи б не сягнуло.
У тому, як ви ним керуєте, нічого не змінюється. Та сама команда, те саме вікно, та сама панель сесії з двома годинниками й вердиктом.
# Та сама команда, що й для нативного застосунку — режим визначається сам chrono run "%LOCALAPPDATA%\Programs\your-app\YourApp.exe" --at 2038-01-01T00:00:00 --mode x60
Два обмеження, про які варто знати до початку
Запуск інвазивний, і це навмисно говориться вголос.
Застосунок запускається з відкритим портом віддаленого налагодження й новим ізольованим профілем у
%TEMP% — він не працює на вашому справжньому профілі й це не та копія, що вже
висить у вас в області сповіщень. Профіль видаляється наприкінці сесії, а якщо це не вдалося,
підсумок сесії повідомляє про це, а не залишає його тихо лежати.
Передача вашого власного --user-data-dir або --remote-debugging-port
відхиляється, а не перевизначається, бо очевидну необачність — спрямувати сесію на ваш
справжній профіль браузера — допускати не варто.
Сторінки читають часовий пояс сесії.
Кожна сторінка й кожен воркер переводиться на часовий пояс
сесії, фіксоване зміщення без переходу на літній час, і перевіряє зміщення, яке читає,
тому сторінка, що прочитала інший пояс, потрапляє у звіт. Два обмеження: Intl
називає цей пояс зміщенням на кшталт GMT+02:00, а не містом, а головний процес
застосунку Electron виконує JavaScript у Node, куди сесія не сягає, тому він залишається на
справжньому годиннику - звіт про це каже.
Ще одне, що дивує людей: інтервал, уже поставлений у розклад, зберігає колишній
темп, коли ви змінюєте швидкість посеред сесії. Date.now,
new Date() і performance.now реагують одразу, а працюючий
setInterval — ні, і сесія попереджає про це, а не дозволяє дійти висновку, що
зміна нічого не зробила.
Наскільки добре це перевірено
Експериментально, і в цього слова тут визначений зміст: воно працює на тих цілях, під які створювалося, не перевірялося широко, а вбудований аудит — ваше джерело істини, а не ця сторінка. Перевірено вручну, а не автоматичним набором, на справжньому застосунку Electron у 64-розрядній Windows.
Покриття повідомляється за контекстами JavaScript, а не за процесами, оскільки саме ця одиниця тут існує. Застосунок, що простоює й ніколи не питає час, чесно дає не визначено — він не читав годинник, тож не можна стверджувати, чи побачив би він правильний. Що означають вердикти →