Permalink
Browse files

fix socket and TCP/IP connection. (so all 3 connection methods do wor…

…k now)
  • Loading branch information...
1 parent 4e13035 commit 15595dd2fe65ee8bec77c4118d521af4e7ba4fed @MarcWeber MarcWeber committed with nominolo Jan 19, 2009
View
@@ -24,8 +24,9 @@ module Main where
import Prelude hiding ( log )
import System.Environment (getArgs, getProgName)
import System.Exit (exitSuccess)
-import System.IO (stdin, stdout)
+import System.IO (stdin, stdout, hSetBuffering, BufferMode(..))
import qualified System.Log.Logger as HL
+import qualified System.Log.Handler.Simple as HL
import qualified System.Log.Handler.Syslog as HL
import qualified Data.ByteString.Char8 as S
import Network ( listenOn, PortID(..) )
@@ -75,18 +76,22 @@ options =
"listen on this TCP port"
, Option ['i'] ["stdinout"]
(NoArg (\opts -> return $ opts { connectionMode = StdInOut}))
- "client must connect to stdin and stdout (untested)"
+ "client must connect to stdin and stdout"
#ifndef mingw32_HOST_OS
, Option ['s'] ["socketfile"]
(ReqArg (\o opts -> return $ opts { connectionMode = Socketfile o}) "/tmp/scion-io")
- "listen on this socketfile (untested)"
+ "listen on this socketfile"
#endif
, Option ['h'] ["help"] (NoArg (\opts -> return $ opts { showHelp = True } )) "show this help"
+
+ , Option ['f'] ["log-file"] (ReqArg (\f opts -> do
+ fh <- HL.fileHandler f HL.DEBUG
+ HL.updateGlobalLogger "" (HL.addHandler fh)
+ return opts ) "/tmp/scion-log") "log to the given file"
]
initializeLogging = do
- stdout <- HL.openlog "" [] HL.USER HL.DEBUG
- HL.updateGlobalLogger "" (HL.addHandler stdout) -- add a default logger
+ -- by default log everything to stdout
HL.updateGlobalLogger "" (HL.setLevel HL.DEBUG)
helpText = do
@@ -96,13 +101,17 @@ helpText = do
serve :: ConnectionMode -> IO ()
serve (TCPIP nr) = do
- sock <- liftIO $ listenOn (PortNumber 4005)
- (sock', _addr) <- liftIO $ accept sock
- handleClient sock'
-serve StdInOut = handleClient (stdin, stdout)
+ sock <- liftIO $ listenOn (PortNumber nr)
+ forever $ E.handle (\(e::E.IOException) -> logInfo ("caught :" ++ (show e) ++ "\n\nwaiting for next client")) $ do
+ (sock', _addr) <- liftIO $ accept sock
+ handleClient sock'
+serve StdInOut = do
+ hSetBuffering stdout LineBuffering
+ hSetBuffering stdin LineBuffering
+ handleClient (stdin, stdout)
#ifndef mingw32_HOST_OS
serve (Socketfile file) = do
- sock <- liftIO $ listenOn (PortNumber 4005)
+ sock <- liftIO $ listenOn (UnixSocket file)
forever $ do
-- no multithreading for now (I don't know yet when it may be used.. the
-- ghc library is using some IO refs)
@@ -16,7 +16,7 @@ module Scion.Server.ConnectionIO (
import Control.Exception (throw, IOException, Exception)
-- import System.IO.Error (mkIOError, IOErrorType(..) )
import Prelude hiding (log)
-import System.IO (Handle, hClose, hPutStr, hPutStrLn)
+import System.IO (Handle, hClose, hPutStr, hPutStrLn, hFlush)
import Control.Monad (when)
import Network.Socket (Socket, sClose)
import Network.Socket.ByteString (recv, send)
@@ -39,7 +39,9 @@ instance ConnectionIO (Handle, Handle) where
getLine (i, _) = S.hGetLine i
getN (i,_) = S.hGet i
put (_,o) = S.hPutStr o
- putLine (_,o) = S.hPutStrLn o
+ putLine (_,o) = \l -> do
+ S.hPutStrLn o l
+ hFlush o -- don't ask me why this is needed. LineBuffering is set as well (!)
-- Socket.ByteString implemenation
instance ConnectionIO Socket where
@@ -37,10 +37,10 @@ import qualified System.Log.Logger as HL
import qualified Data.ByteString.Char8 as S
import qualified Data.Map as M
-import Data.List (intercalate)
+import Data.List (intercalate, nub)
import Data.Time.Clock ( NominalDiffTime )
-import DynFlags ( supportedLanguages )
+import DynFlags ( supportedLanguages, allFlags )
import InteractiveEval ( getNamesInScope )
import qualified Outputable as O
import GHC
@@ -186,7 +186,7 @@ cmdListSupportedPragmas = VimCommand "cmdListSupportedPragmas" $ \map' -> do
return $ toVim $ supportedPragmas
cmdListSupportedFlags = VimCommand "cmdListSupportedFlags" $ \map' -> do
- return $ toVim $ supportedPragmas
+ return $ toVim $ nub $ allFlags
cmdListRdrNamesInScope = VimCommand "cmdListRdrNamesInScope" $ \map' -> do
rdr_names <- getNamesInScope
@@ -219,6 +219,7 @@ cmdThingAtPoint = VimCommand "cmdThingAtPoint" $ \map' -> do
col <- lookupAndReadFail map' "col"
liftM toVim $ cmd file line col
where
+ -- TODO remove this code duplication !
cmd fname line col = do
let loc = srcLocSpan $ mkSrcLoc (fsLit fname) line col
tc_res <- gets bgTcCache
@@ -19,8 +19,6 @@ if !has('python') | call s:Log(0, "Error: scion requires vim compiled with +pyth
let g:vim_scion_protocol_version = "0"
-" TODO: implement stdin/ out
-py scionConnectionSetting = ('127.0.0.1', 4005)
" use this to connect to a socket
" py scionConnectionSetting = "/tmp/scion-io"
@@ -63,47 +61,87 @@ endfunction
function! s:DefPython()
python << PYTHONEOF
-import sys, tokenize, cStringIO, types, socket, string, vim
+import sys, tokenize, cStringIO, types, socket, string, vim, popen2
+from subprocess import Popen, PIPE
-scionsocketFile = None
-lastScionResult = "";
-def connectscion():
- # TODO add stdin out support
- if type(scionConnectionSetting) == type((0,0)):
+
+class ScionServerConnection:
+ """base of a server connection. They all provide two methods: send and receive bothe sending or receiving a single line separated by \\n"""
+ def send(self, line):
+ self.scion_i.write("%s\n"%line)
+ self.scion_i.flush()
+ def receive(self):
+ return self.scion_o.readline()[:-1]
+
+class ScionServerConnectionStdinOut(ScionServerConnection):
+ """this connection launches the server and connects to its stdin and stdout streams"""
+ def __init__(self, scion_executable):
+ #self.scion_o,self.scion_i,e = popen2.popen3('%s -i -f /tmp/scion-log'%(scion_executable))
+ p = Popen([scion_executable,"-i","-f", "/tmp/scion-log"], shell = False, bufsize = 1, stdin = PIPE, stdout = PIPE, stderr = PIPE)
+ self.scion_o = p.stdout
+ self.scion_i = p.stdin
+
+class ScionServerConnectionSocket(ScionServerConnection):
+ """connects to the scion server by either TCP/IP or socketfile"""
+ def __init__(self, connection):
+ # connection either (host, port) or (socketfile)
+ if type(connection) == type((0,0)):
# tuple -> host, port
- print "scion: connecting to adress", scionConnectionSetting
su = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
else: # must be path -> file socket
- print "scion: connecting to file socket", scionConnectionSetting
su = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
su.settimeout(10)
- su.connect(scionConnectionSetting)
+ su.connect(connection)
+ # making file to use readline()
+ self.scion_o = su.makefile('rw')
+ self.scion_i = self.scion_o
+
+server_connection = None
+told_user_about_missing_configuration = 0
+lastScionResult = "";
+def connectscion():
+ # check that connection method has been defined
+ global server_connection
+ global told_user_about_missing_configuration
+ if 0 == told_user_about_missing_configuration:
+ try:
+ print scionConnectionSetting
+ except NameError:
+ vim.command("sp")
+ b = vim.current.buffer
+ b.append( "you haven't defined scionConnectionSetting")
+ b.append( "Do so by adding one of the following lines to your .vimrc:")
+ b.append( "TCP/IP, socket, stdio")
+ b.append( "py scionConnectionSetting = ('socket', \"socket file location\") # socket connection")
+ b.append( "py scionConnectionSetting = ('socket', (127.0.0.1', 4005)) # host, port TCIP/IP connection")
+ b.append( "py scionConnectionSetting = ('scion', \"scion_server location\") # stdio connection ")
+ told_user_about_missing_configuration = 1
+
+ if scionConnectionSetting[0] == "socket":
+ server_connection = ScionServerConnectionSocket(scionConnectionSetting[1])
+ else:
+ server_connection = ScionServerConnectionStdinOut(scionConnectionSetting[1])
+
# handshake
- su.send("select scion-server protocol:vim %s\n" % vim.eval('g:vim_scion_protocol_version'));
- # using file interface to be able to use readline..
- file = su.makefile('rw')
- res = file.readline()
- if res != "ok\n":
+ server_connection.send("select scion-server protocol:vim %s" % vim.eval('g:vim_scion_protocol_version'))
+ res = server_connection.receive()
+ if res != "ok":
raise Exception("failed connecting to scion Reason: `%s'" % res)
- else:
- return file
# sends a command and returns the returned line
def evalscion(str):
- global scionsocketFile
- if (scionsocketFile == None):
- scionsocketFile = connectscion()
+ global server_connection
try:
- scionsocketFile.write(str + "\n")
+ server_connection.send(str)
except:
- vim.command('echoe "%s"' % "lost connection ? trying reconnect")
- scionsocketFile = connectscion()
- scionsocketFile.write(str + "\n")
- scionsocketFile.flush()
- return scionsocketFile.readline()
+ vim.command('echoe "%s"'% ("(re) connecting to scion"))
+ connectscion()
+ server_connection.send(str)
+ return server_connection.receive()
# str see EvalScion
def evalscionAssign(str):
+ global lastScionResult
"""assigns scion result to g:scion_result, result should either be
{ "result" : ..., "error" : [String] }"""
vim.command("silent! unlet g:scion_result")

0 comments on commit 15595dd

Please sign in to comment.