Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/telega-ellit.org
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ Make =telega= know you want to use docker by adding this to your =init.el=:
(setq telega-use-docker t)
#+end_src

On Windows, =telega= rewrites Docker bind mounts and TDLib file paths
for Docker Desktop automatically. If you need to start the image
manually from PowerShell, use a Linux container path, for example:
#+begin_src powershell
docker run --rm -it -v ${HOME}/.telega:/telega zevlg/telega-server:latest /usr/bin/telega-server
#+end_src

That's it, you are ready to get starting. However, you might anyway
need to have local =ffmpeg= installation to utilize some =telega=
features, such as playing audio/voice messages, capturing video/voice
Expand Down
7 changes: 7 additions & 0 deletions docs/telega-manual.org
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ Make =telega= know you want to use docker by adding this to your =init.el=:
(setq telega-use-docker t)
#+end_src

On Windows, =telega= rewrites Docker bind mounts and TDLib file paths
for Docker Desktop automatically. If you need to start the image
manually from PowerShell, use a Linux container path, for example:
#+begin_src powershell
docker run --rm -it -v ${HOME}/.telega:/telega zevlg/telega-server:latest /usr/bin/telega-server
#+end_src

That's it, you are ready to get starting. However, you might anyway
need to have local =ffmpeg= installation to utilize some =telega=
features, such as playing audio/voice messages, capturing video/voice
Expand Down
3 changes: 2 additions & 1 deletion etc/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# docker build -f etc/Dockerfile -t zevlg/telega-server:latest .
# docker tag $(docker images -q zevlg/telega-server:latest) zevlg/telega-server:latest
# docker push zevlg/telega-server:latest
# docker run -v $HOME/.telega:$HOME/.telega zevlg/telega-server:latest /usr/bin/telega-server
# docker run -v $HOME/.telega:/telega zevlg/telega-server:latest /usr/bin/telega-server
# PowerShell: docker run -v ${HOME}/.telega:/telega zevlg/telega-server:latest /usr/bin/telega-server

### Release image
# docker build --build-arg tdlib_branch=v1.8.0 --build-arg telega_branch=release-0.8.0 -f etc/Dockerfile -t zevlg/telega-server:1.8.0 .
Expand Down
143 changes: 138 additions & 5 deletions telega-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -1247,17 +1247,150 @@ If NO-PROPERTIES is specified, then do not keep text properties."
#'telega--desurrogate-apply-part-keep-properties)
(telega--split-by-text-prop str 'telega-display) ""))

(defconst telega-docker--windows-container-root "/telega"
"Container root used for Windows Docker bind mounts.")

(defsubst telega-docker--windows-p ()
"Return non-nil if telega runs on Windows."
(eq system-type 'windows-nt))

(defun telega-docker--normalize-path (path)
"Return PATH expanded with forward slashes and no trailing slash."
(directory-file-name
(replace-regexp-in-string "\\\\" "/" (expand-file-name path))))

(defun telega-docker--normalize-container-path (path)
"Return container PATH normalized for comparisons."
(directory-file-name
(replace-regexp-in-string "\\\\" "/" path)))

(defun telega-docker--path-prefix-p (path prefix)
"Return non-nil if PATH is equal to PREFIX or is inside it."
(let ((norm-path (downcase (telega-docker--normalize-path path)))
(norm-prefix (downcase (telega-docker--normalize-path prefix))))
(or (string= norm-path norm-prefix)
(string-prefix-p (concat norm-prefix "/") norm-path))))

(defun telega-docker--container-path-prefix-p (path prefix)
"Return non-nil if container PATH is equal to PREFIX or is inside it."
(let ((norm-path (telega-docker--normalize-container-path path))
(norm-prefix (telega-docker--normalize-container-path prefix)))
(or (string= norm-path norm-prefix)
(string-prefix-p (concat norm-prefix "/") norm-path))))

(defun telega-docker--path-mappings ()
"Return Docker bind mount mappings for current telega runtime."
(when (and telega-use-docker (telega-docker--windows-p))
(let ((mappings
(list (cons (telega-docker--normalize-path telega-directory)
telega-docker--windows-container-root))))
(dolist (path-spec
`((,telega-database-dir . "db")
(,telega-cache-dir . "cache")
(,telega-temp-dir . "temp")
(,(when telega-server-logfile
(file-name-directory telega-server-logfile))
. "logs")))
(when-let ((host-path (car path-spec)))
(setq host-path (telega-docker--normalize-path host-path))
(unless (seq-some
(lambda (mapping)
(telega-docker--path-prefix-p host-path (car mapping)))
mappings)
(push (cons host-path
(concat telega-docker--windows-container-root
"/" (cdr path-spec)))
mappings))))
(sort mappings (lambda (lhs rhs)
(> (length (car lhs)) (length (car rhs))))))))

(defun telega-docker-path-to-container (path)
"Translate host PATH into its container path."
(if (not (and path telega-use-docker (telega-docker--windows-p)))
path
(let ((norm-path (telega-docker--normalize-path path)))
(or (seq-some
(lambda (mapping)
(when (telega-docker--path-prefix-p norm-path (car mapping))
(concat (cdr mapping)
(substring norm-path (length (car mapping))))))
(telega-docker--path-mappings))
path))))

(defun telega-docker-path-to-host (path)
"Translate container PATH back to its host path."
(if (not (and path telega-use-docker (telega-docker--windows-p)))
path
(let ((norm-path (telega-docker--normalize-container-path path)))
(or (seq-some
(lambda (mapping)
(when (telega-docker--container-path-prefix-p norm-path (cdr mapping))
(concat (car mapping)
(substring norm-path (length (cdr mapping))))))
(telega-docker--path-mappings))
path))))

(defun telega-docker-cmd-to-container (cmd)
"Translate known host paths inside shell CMD into container paths."
(if (not (and cmd telega-use-docker (telega-docker--windows-p)))
cmd
(let ((mapped-cmd cmd))
(dolist (mapping (telega-docker--path-mappings) mapped-cmd)
(setq mapped-cmd
(replace-regexp-in-string
(regexp-quote (car mapping)) (cdr mapping)
mapped-cmd 'fixedcase 'literal))))))

(defun telega-docker--tl-path-transform (obj direction)
"Translate Docker file paths inside TL object OBJ.
DIRECTION is either the symbol `to-container' or `to-host'."
(if (not (and telega-use-docker (telega-docker--windows-p)))
obj
(cond ((vectorp obj)
(cl-map 'vector
(lambda (elem)
(telega-docker--tl-path-transform elem direction))
obj))
((consp obj)
(let ((obj-type (plist-get obj :@type))
(mapped-obj
(mapcar (lambda (elem)
(telega-docker--tl-path-transform elem direction))
obj)))
(cond ((and (equal obj-type "inputFileLocal")
(eq direction 'to-container))
(plist-put mapped-obj :path
(telega-docker-path-to-container
(plist-get mapped-obj :path))))
((and (equal obj-type "localFile")
(eq direction 'to-host))
(plist-put mapped-obj :path
(telega-docker-path-to-host
(plist-get mapped-obj :path))))
((and (equal obj-type "setTdlibParameters")
(eq direction 'to-container))
(plist-put mapped-obj :database_directory
(telega-docker-path-to-container
(plist-get mapped-obj :database_directory)))
(plist-put mapped-obj :files_directory
(telega-docker-path-to-container
(plist-get mapped-obj :files_directory)))))
mapped-obj))
(t obj))))

(defsubst telega--tl-unpack (obj)
"Unpack TL object OBJ."
obj)
(telega-docker--tl-path-transform obj 'to-host))

(defsubst telega--tl-pack (obj)
"Pack object OBJ."
;; Remove text props from strings, etc
(cond ((stringp obj) (substring-no-properties obj))
((vectorp obj) (cl-map 'vector #'telega--tl-pack obj))
((listp obj) (mapcar #'telega--tl-pack obj))
(t obj)))
(telega-docker--tl-path-transform
(cond ((stringp obj) (substring-no-properties obj))
((vectorp obj) (cl-map 'vector #'telega--tl-pack obj))
((listp obj) (mapcar #'telega--tl-pack obj))
(t obj))
'to-container))

(defun telega-tl-str (obj &optional prop no-properties)
"Get property PROP from OBJ, desurrogating resulting string.
Expand Down
32 changes: 22 additions & 10 deletions telega-server.el
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,28 @@ Set `telega-server-libs-prefix' to the TDLib installion path"
"Create command to start `telega-server' progress.
FLAGS - additional.
Raise error if not found."
(mapconcat #'identity
(cons
(if telega-use-docker
(telega-docker-run-cmd telega-server-command)
(let ((exec-path (cons telega-directory exec-path)))
(or (executable-find telega-server-command)
(error "`%s' not found in exec-path"
telega-server-command))))
flags)
" "))
(let ((flags (delq nil flags)))
(if (and telega-use-docker
(telega-docker--windows-p))
(mapconcat
#'identity
(cons (telega-docker-run-cmd telega-server-command)
(mapcar (lambda (flag)
(shell-quote-argument
(telega-docker-cmd-to-container flag)))
flags))
" ")
(mapconcat
#'identity
(cons
(if telega-use-docker
(telega-docker-run-cmd telega-server-command)
(let ((exec-path (cons telega-directory exec-path)))
(or (executable-find telega-server-command)
(error "`%s' not found in exec-path"
telega-server-command))))
flags)
" "))))

(defun telega-server-version ()
"Return telega-server version."
Expand Down
7 changes: 4 additions & 3 deletions telega-tdlib-events.el
Original file line number Diff line number Diff line change
Expand Up @@ -1311,9 +1311,10 @@ Please downgrade TDLib and recompile `telega-server'"
(authorizationStateWaitTdlibParameters
;; Tune permissions for docker's /dev/snd, /dev/video*
(when-let ((devices-chown-cmd
(telega-docker-exec-cmd
"chmod -R o+rw /dev/snd /dev/video0" nil
"-u 0" 'no-error)))
(unless (telega-docker--windows-p)
(telega-docker-exec-cmd
"chmod -R o+rw /dev/snd /dev/video0" nil
"-u 0" 'no-error))))
(telega-debug "docker RUN: %s" devices-chown-cmd)
(shell-command-to-string devices-chown-cmd))

Expand Down
Loading