Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Unix domain socket support #418

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
48 changes: 38 additions & 10 deletions autoload/fireplace.vim
Original file line number Diff line number Diff line change
@@ -587,8 +587,9 @@ function! fireplace#register_port_file(portfile, ...) abort
endif
if empty(old) && getfsize(portfile) > 0
let port = matchstr(readfile(portfile, 'b', 1)[0], '\d\+')
let url = s:build_url(port)
try
let transport = fireplace#transport#connect(port)
let transport = fireplace#transport#connect(url, 'nrepl')
let session = transport.Clone()
let s:repl_portfiles[portfile] = {
\ 'time': getftime(portfile),
@@ -626,10 +627,24 @@ function! fireplace#ConnectComplete(A, L, P) abort
return options
endfunction

function! s:build_url(arg) abort
let url = a:arg
if url =~# '^\d\+$'
let url = 'nrepl://localhost:' . url
elseif url =~# '^[^:/@]\+\(:\d\+\)\=$'
let url = 'nrepl://' . url
elseif url !~# '^\a\+://'
throw "Fireplace: invalid connection string " . string(a:arg)
endif
let url = substitute(url, '^\a\+://[^/]*\zs$', '/', '')
let url = substitute(url, '^nrepl://[^/:]*\zs/', ':7888/', '')
return url
endfunction

function! fireplace#ConnectCommand(line1, line2, range, bang, mods, arg, args) abort
let str = get(a:args, 0, '')
if empty(str)
let str = input('Port or URL: ')
let str = input('Port, path, or URL: ')
if empty(str)
return ''
endif
@@ -638,17 +653,30 @@ function! fireplace#ConnectCommand(line1, line2, range, bang, mods, arg, args) a
if str =~# '^[%#]'
let str = expand(str)
endif
if str !~# '^\d\+$\|:\d\|:[\/][\/]' && filereadable(str)
let path = fnamemodify(str, ':p:h')
let str = readfile(str, '', 1)[0]
elseif str !~# '^\d\+$\|:\d\|:[\/][\/]' && filereadable(str . '/.nrepl-port')
let path = fnamemodify(str, ':p:h')
let str = readfile(str . '/.nrepl-port', '', 1)[0]
else

let filestring = str !~# '^\d\+$\|:\d\|:[\/][\/]'
if filestring && getftype(resolve(str)) == 'socket'
" User specified a path resolving to an AF_UNIX socket, so pass the path
" through without modification
let path = fnamemodify(exists('b:java_root') ? b:java_root : getcwd(), ':~')
let scheme = 'nrepl'
else
" User specified a URL or a string pointing to a file that contains a
" port number. Construct a URL then use it to determine the scheme
if filestring && filereadable(str)
let path = fnamemodify(str, ':p:h')
let str = readfile(str, '', 1)[0]
elseif filestring && filereadable(str . '/.nrepl-port')
let path = fnamemodify(str, ':p:h')
let str = readfile(str . '/.nrepl-port', '', 1)[0]
else
let path = fnamemodify(exists('b:java_root') ? b:java_root : getcwd(), ':~')
endif
let str = s:build_url(str)
let scheme = matchstr(str, '^\a\+')
endif
try
let transport = fireplace#transport#connect(str)
let transport = fireplace#transport#connect(str, scheme)
catch /.*/
return 'echoerr '.string(v:exception)
endtry
31 changes: 10 additions & 21 deletions autoload/fireplace/transport.vim
Original file line number Diff line number Diff line change
@@ -168,35 +168,24 @@ augroup fireplace_transport
\ | endfor
augroup END

function! fireplace#transport#connect(arg) abort
let url = substitute(a:arg, '#.*', '', '')
if url =~# '^\d\+$'
let url = 'nrepl://localhost:' . url
elseif url =~# '^[^:/@]\+\(:\d\+\)\=$'
let url = 'nrepl://' . url
elseif url !~# '^\a\+://'
throw "Fireplace: invalid connection string " . string(a:arg)
function! fireplace#transport#connect(str, scheme) abort
if has_key(s:urls, a:str)
return s:urls[a:str].transport
endif
let url = substitute(url, '^\a\+://[^/]*\zs$', '/', '')
let url = substitute(url, '^nrepl://[^/:]*\zs/', ':7888/', '')
if has_key(s:urls, url)
return s:urls[url].transport
endif
let scheme = matchstr(url, '^\a\+')
if scheme ==# 'nrepl'
if a:scheme ==# 'nrepl'
let command = [g:fireplace_python_executable, s:python_dir.'/fireplace.py']
elseif exists('g:fireplace_argv_' . scheme)
let command = g:fireplace_argv_{scheme}
elseif exists('g:fireplace_argv_' . a:scheme)
let command = g:fireplace_argv_{a:scheme}
else
throw 'Fireplace: unsupported protocol ' . scheme
throw 'Fireplace: unsupported protocol ' . a:scheme
endif
let transport = deepcopy(s:transport)
let transport.url = url
let transport.url = a:str
let transport.state = {}
let transport.sessions = {}
let transport.requests = {}
let cb_args = [url, transport.state, transport.requests, transport.sessions]
let transport.job = s:json_start(command + [url], function('s:json_callback', cb_args), function('s:exit_callback', cb_args))
let cb_args = [a:str, transport.state, transport.requests, transport.sessions]
let transport.job = s:json_start(command + [a:str], function('s:json_callback', cb_args), function('s:exit_callback', cb_args))
while !has_key(transport.state, 'status') && transport.Alive()
sleep 1m
endwhile
43 changes: 31 additions & 12 deletions pythonx/fireplace.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
import os
import re
import socket
import stat
import sys
import traceback
import threading
@@ -92,18 +93,39 @@ def quickfix(t, e, tb):
'text': line})
return {'title': str(e), 'items': items}


def parse_dest(dest):
match = re.search('//([^:/@]+)(?::(\d+))?', dest)
if match is not None:
host = match.groups()[0]
port = match.groups()[1]
return (None, host, int(port or 7888))
elif os.path.exists(dest) and stat.S_ISSOCK(os.stat(dest).st_mode):
return (dest, None, None)
else:
raise ValueError("Connection string must be a URL or a path to a socket file")


class Connection:
def __init__(self, host, port, keepalive_file=None):
def __init__(self, dest, keepalive_file=None):
parsed_dest = parse_dest(dest)
(path, host, port) = parse_dest(dest)
self.path = path
self.host = host
self.port = port
self.keepalive_file = keepalive_file
self.connected = False
self.host = host
self.port = int(port)

def socket(self):
if not self.connected:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(8)
s.connect((self.host, self.port))
if self.path:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.settimeout(8)
s.connect(self.path)
else:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(8)
s.connect((self.host, self.port))
s.setblocking(1)
self._socket = s
self.connected = True
@@ -176,13 +198,10 @@ def tunnel(self):
self.notify(["exception", quickfix(*sys.exc_info())])
os._exit(3)

def main(host = None, port = None, *args):

def main(dest = None, *args):
try:
match = re.search('//([^:/@]+)(?::(\d+))?', host)
if match:
host = match.groups()[0]
port = match.groups()[1]
conn = Connection(host, int(port or 7888))
conn = Connection(dest)
try:
conn.tunnel()
finally: