2012-05-07 14:41:15 +02:00
;;; ein-websocket.el --- Wrapper of websocket.el
;; Copyright (C) 2012- Takafumi Arakaki
2012-07-01 20:18:05 +02:00
;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
2012-05-07 14:41:15 +02:00
;; This file is NOT part of GNU Emacs.
;; ein-websocket.el is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; ein-websocket.el is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with ein-websocket.el. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
( eval-when-compile ( require 'cl ) )
( require 'websocket )
2012-08-28 15:26:32 +02:00
( require 'ein-core )
2017-07-12 14:38:04 -05:00
( require 'ein-classes )
2015-06-29 07:07:53 -05:00
( require 'url-cookie )
2016-12-14 12:32:26 -06:00
( require 'request )
2012-05-07 14:41:15 +02:00
2016-12-14 12:32:26 -06:00
;; Fix issues reading cookies in request when using curl backend
( defun fix-request-netscape-cookie-parse ( next-method )
" Parse Netscape/Mozilla cookie format. "
( goto-char ( point-min ) )
( let ( ( tsv-re ( concat " ^ \\ = "
( cl-loop repeat 6 concat " \\ ([^ \t \n ]+ \\ ) \t " )
" \\ (.* \\ ) " ) )
cookies )
( forward-line 3 ) ;; Skip header (first three lines)
( while
( and
( cond
( ( re-search-forward " ^ \\ =$ " nil t ) )
( ( re-search-forward tsv-re )
( push ( cl-loop for i from 1 to 7 collect ( match-string i ) )
cookies )
t ) )
( = ( forward-line 1 ) 0 )
( not ( = ( point ) ( point-max ) ) ) ) )
( setq cookies ( nreverse cookies ) )
( cl-loop for ( domain flag path secure expiration name value ) in cookies
collect ( list domain
( equal flag " TRUE " )
path
( equal secure " TRUE " )
( string-to-number expiration )
name
value ) ) ) )
2016-12-22 12:19:52 -06:00
;;(advice-add 'request--netscape-cookie-parse :around #'fix-request-netscape-cookie-parse)
2016-12-14 12:32:26 -06:00
2018-09-18 21:46:35 -05:00
;; Websocket gets its cookies using the url-cookie API, so we need to copy over
;; any cookies that are made and stored during the contents API calls via
;; emacs-request.
2015-06-29 07:07:53 -05:00
( defun ein:websocket--prepare-cookies ( url )
2017-07-25 16:57:32 -05:00
( let* ( ( jh-conn ( ein:jupyterhub-url-p url ) )
( parsed-url ( url-generic-parse-url url ) )
2015-06-29 07:07:53 -05:00
( host-port ( if ( url-port-if-non-default parsed-url )
( format " %s:%s " ( url-host parsed-url ) ( url-port parsed-url ) )
( url-host parsed-url ) ) )
2016-04-08 21:22:14 -05:00
( securep ( string-match " ^wss:// " url ) )
2016-12-13 17:47:23 -06:00
( http-only-cookies ( request-cookie-alist ( concat " #HttpOnly_ " ( url-host ( url-generic-parse-url url ) ) ) " / " securep ) ) ;; Current version of Jupyter store cookies as HttpOnly)
2017-07-25 16:57:32 -05:00
( cookies ( request-cookie-alist ( url-host ( url-generic-parse-url url ) ) " / " securep ) )
( hub-cookies ( request-cookie-alist ( url-host ( url-generic-parse-url url ) ) " /hub/ " securep ) )
( user-cookies ( and jh-conn
( request-cookie-alist
( url-host ( url-generic-parse-url url ) )
( ein:$jh-user-server ( ein:$jh-conn-user jh-conn ) )
securep ) ) ) )
( when ( or cookies http-only-cookies hub-cookies user-cookies )
2018-02-14 18:24:20 -06:00
( ein:log 'debug " EIN:WEBSOCKET--PREPARE-COOKIES Storing cookies in prep for opening websocket (%s) " cookies )
2017-07-25 16:57:32 -05:00
( dolist ( c ( append cookies http-only-cookies hub-cookies user-cookies ) )
2016-04-08 21:22:14 -05:00
( url-cookie-store ( car c ) ( cdr c ) nil host-port ( car ( url-path-and-query parsed-url ) ) securep ) ) ) ) )
2015-06-29 07:07:53 -05:00
2018-10-30 14:17:29 -04:00
( defun ein:websocket ( url kernel on-message on-close on-open )
2015-06-29 07:07:53 -05:00
( ein:websocket--prepare-cookies url )
2018-10-30 14:17:29 -04:00
( let* ( ( ws ( websocket-open url
:on-open on-open
:on-message on-message
:on-close on-close
:on-error ( lambda ( ws action err )
2018-11-01 20:08:10 -04:00
( ein:log 'info " WS action [%s] %s (%s) "
2018-10-30 14:17:29 -04:00
err action ( websocket-url ws ) ) ) ) )
( websocket ( make-ein:$websocket :ws ws :kernel kernel :closed-by-client nil ) ) )
2012-06-01 22:11:34 +02:00
( setf ( websocket-client-data ws ) websocket )
2012-05-07 14:41:15 +02:00
websocket ) )
2012-05-13 16:23:57 +02:00
( defun ein:websocket-open-p ( websocket )
2012-06-01 22:56:09 +02:00
( eql ( websocket-ready-state ( ein:$websocket-ws websocket ) ) 'open ) )
2012-05-13 16:23:57 +02:00
2012-05-07 14:41:15 +02:00
( defun ein:websocket-send ( websocket text )
2014-10-22 21:35:20 -05:00
;; (ein:log 'info "WS: Sent message %s" text)
2016-12-22 12:19:52 -06:00
( condition-case-unless-debug err
( websocket-send-text ( ein:$websocket-ws websocket ) text )
( error ( message " Error %s on sending websocket message %s. " err text ) ) ) )
2012-05-07 14:41:15 +02:00
( defun ein:websocket-close ( websocket )
2012-05-09 08:54:02 +02:00
( setf ( ein:$websocket-closed-by-client websocket ) t )
2012-05-07 14:41:15 +02:00
( websocket-close ( ein:$websocket-ws websocket ) ) )
2015-01-14 17:07:28 -06:00
( defun ein:websocket-send-shell-channel ( kernel msg )
( cond ( ( = ( ein:$kernel-api-version kernel ) 2 )
( ein:websocket-send
( ein:$kernel-shell-channel kernel )
( json-encode msg ) ) )
2016-11-05 17:49:52 -05:00
( ( >= ( ein:$kernel-api-version kernel ) 3 )
2015-01-14 17:07:28 -06:00
( ein:websocket-send
2018-10-30 14:17:29 -04:00
( ein:$kernel-websocket kernel )
2015-01-14 17:07:28 -06:00
( json-encode ( plist-put msg :channel " shell " ) ) ) ) ) )
2015-03-31 16:55:14 -05:00
( defun ein:websocket-send-stdin-channel ( kernel msg )
( cond ( ( = ( ein:$kernel-api-version kernel ) 2 )
( ein:log 'warn " Stdin messages only supported with IPython 3. " ) )
2016-11-05 17:49:52 -05:00
( ( >= ( ein:$kernel-api-version kernel ) 3 )
2015-03-31 16:55:14 -05:00
( ein:websocket-send
2018-10-30 14:17:29 -04:00
( ein:$kernel-websocket kernel )
2015-03-31 16:55:14 -05:00
( json-encode ( plist-put msg :channel " stdin " ) ) ) ) ) )
2012-05-07 14:41:15 +02:00
( provide 'ein-websocket )
;;; ein-websocket.el ends here