Перейти к содержимому

Календарь и планирование

Control Center подключается к Google Calendar, чтобы ваш день был рядом с вашим флотом. Он синхронизирует события, показывает их в представлениях «Месяц», «Неделя», «День» и «Расписание», предупреждает перед началом встречи и превращает любое событие в записанную, резюмированную встречу.

Почти ничего. Интеграция загружает события и отображает их. Она не создаёт, не редактирует, не удаляет события и не отвечает на приглашения. Любое подключение по коду устройства — встроенное или с собственными учётными данными — запрашивает calendar.readonly и openid email.

События синхронизируются в собственную базу данных рабочего пространства на сервере (<dataDir>/<workspaceId>/workspace.db) и отображаются каждым клиентом по RPC. Ни один клиент не хранит учётные данные Google.

Аккаунты для каждого рабочего пространства

Заголовок раздела «Аккаунты для каждого рабочего пространства»

Аккаунты календаря принадлежат рабочему пространству, как и всё остальное в Control Center. Каждое рабочее пространство подключает свой аккаунт Google (или несколько), и события и токены одного рабочего пространства никогда не видны из другого. Переключение рабочего пространства меняет и календари, которые вы видите.

Рабочее пространство может подключить несколько аккаунтов Google, например рабочий и личный, и их события объединяются в одних и тех же представлениях.

Почему вход выполняется через код устройства

Заголовок раздела «Почему вход выполняется через код устройства»

У headless cc_server нет браузера, который мог бы принять перенаправление OAuth. Поэтому он его и не использует: он авторизуется с помощью предоставления кода устройства (RFC 8628). Сервер показывает короткий код пользователя и URL Google, вы подтверждаете на любом устройстве с браузером, а сервер опрашивает, пока вы это не сделаете. Headless-установка может подключить аккаунт именно потому, что ей не нужно размещать конечную точку перенаправления.

Что важно знать, прежде чем использовать свои учётные данные: тип клиента должен быть «TV and Limited Input devices» от Google. Google выдаёт этому типу клиента только набор областей из списка разрешённых, и проект, в котором Calendar для него не разрешён, завершается ошибкой invalid_scope — вместо этого понадобится клиент loopback или веб-клиент.

Токены никогда не покидают сервер. Они записываются в secrets.json сервера в его каталоге данных с ключом google_google:<workspaceId>:<email>, рядом с базами данных и в той же границе доверия файловой системы хоста. Сервер автоматически обновляет доступ и, когда Google окончательно признаёт аккаунт недействительным (отозванный или давно истёкший сеанс), публикует CalendarAuthExpired и показывает баннер Подключить снова, а не молча отказывает.

Сборка из исходного кода вообще не содержит учётных данных Google — вы указываете свой идентификатор клиента и секрет. Официальные сборки релизов включают неконфиденциальный клиент с кодом устройства, чтобы подключение работало из коробки; сервер хранит лишь маркер, ссылающийся на него, а не его копию. GOOGLE_OAUTH_CLIENT_ID (и его секрет) в окружении всегда имеют приоритет над встроенной парой. Флага --google-client-id намеренно нет: неизвестные флаги игнорируются, а секрет в командной строке можно прочитать через ps.

Чтобы запустить собственный проект Google, см. Подключить Google Calendar.

Сервер загружает скользящее окно событий каждого подключённого аккаунта — все календари аккаунта, а не только основной — каждые две минуты, а также по запросу (при запуске, подключении, ручном обновлении). Столь частый цикл оправдан, потому что обход инкрементальный: у каждого календаря есть собственный токен синхронизации, поэтому неизменившийся календарь стоит одного почти пустого ответа, а не повторной загрузки окна в пять месяцев.

Повторяющиеся события разворачиваются на стороне сервера, поэтому ни один клиент не разбирает правило повторения. При переходе к месяцу за пределами текущего окна этот диапазон загружается лениво. Удалённые события и события, перемещённые за пределы диапазона, отсеиваются при следующей синхронизации.

Представление Что показывает
Месяц Сетка на весь месяц (работает на пакете kalender)
Неделя События недели с указанием времени в сетке времени
День События одного дня с указанием времени в сетке времени
Расписание Прокручиваемый список предстоящих событий

Откройте календарь по адресу /calendar; выбор события открывает его подробности по адресу /calendar/:eventId. Выбранное представление хранится в собственных настройках этого клиента, поэтому оно не переносится на другое устройство.

Планировщик, запускаемый раз в минуту, ищет события, начинающиеся в пределах настраиваемого окна опережения, и отправляет уведомление «Встреча скоро начнётся» (доменное событие MeetingStartingSoon). Если у события есть ссылка для подключения, уведомление несёт её, а нажатие открывает подробности события. Оповещения дедуплицируются по полю alertedAt события, поэтому одна и та же встреча никогда не оповещает дважды, даже при перезапусках, а событие, начало которого прошло, пока приложение было закрыто, не воспроизводится.

Есть два ограничения, о которые легко споткнуться. Планировщик работает на стороне клиента, в настольном приложении, и только для рабочего пространства, открытого в данный момент, — для рабочего пространства, в котором вы не находитесь, оповещение не срабатывает. А в веб-сборке вообще нет канала системных уведомлений, поэтому там оповещения тоже не появляются.

Из события календаря можно запустить запись встречи, начальное название которой берётся из события. Control Center хранит связь один к одному между записью и событием, поэтому заметки встречи и запись в календаре остаются связанными, хотя ни одна из функций не зависит от другой.

Начать запись и привязать доступно только в настольном приложении. В веб-клиенте действие сообщает, что запись недоступна, — хотя собственный процесс записи на экране встреч в браузере всё же работает.