This commit is contained in:
Hackerpilot 2016-01-27 00:58:55 -08:00
commit 636e31edfb
11 changed files with 145 additions and 60 deletions

3
.gitignore vendored
View File

@ -18,6 +18,9 @@ perf.data.old
# Valgrind reports # Valgrind reports
callgrind.* callgrind.*
# GDB temp files
.gdb_history
# Git hash file # Git hash file
githash.txt githash.txt

View File

@ -23,6 +23,7 @@ dmd^
src\client\client.d^ src\client\client.d^
src\common\messages.d^ src\common\messages.d^
src\common\dcd_version.d^ src\common\dcd_version.d^
src\common\socket.d^
msgpack-d\src\msgpack.d^ msgpack-d\src\msgpack.d^
-Imsgpack-d\src^ -Imsgpack-d\src^
-release -inline -O -wi^ -release -inline -O -wi^

View File

@ -30,13 +30,14 @@ import std.conv;
import std.string; import std.string;
import std.experimental.logger; import std.experimental.logger;
import msgpack;
import common.messages; import common.messages;
import common.dcd_version; import common.dcd_version;
import common.socket; import common.socket;
int main(string[] args) int main(string[] args)
{ {
sharedLog.fatalHandler = () {};
size_t cursorPos = size_t.max; size_t cursorPos = size_t.max;
string[] importPaths; string[] importPaths;
ushort port = 9166; ushort port = 9166;
@ -106,24 +107,12 @@ int main(string[] args)
if (query) if (query)
{ {
try if (serverIsRunning(useTCP, socketFile, port))
{ {
Socket socket = createSocket(socketFile, port); writeln("Server is running");
scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } return 0;
request.kind = RequestKind.query;
if (sendRequest(socket, request))
{
const AutocompleteResponse response = getResponse(socket);
if (response.completionType == "ack")
{
writeln("Server is running");
return 0;
}
else
throw new Exception("");
}
} }
catch (Exception ex) else
{ {
writeln("Server is not running"); writeln("Server is not running");
return 1; return 1;
@ -312,47 +301,26 @@ Socket createSocket(string socketFile, ushort port)
} }
else else
{ {
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); version(Windows)
socket.connect(new UnixAddress(socketFile)); {
// should never be called with non-null socketFile on Windows
assert(false);
}
else
{
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
socket.connect(new UnixAddress(socketFile));
}
} }
socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5)); socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5));
socket.blocking = true; socket.blocking = true;
return socket; return socket;
} }
/**
* Returns: true on success
*/
bool sendRequest(Socket socket, AutocompleteRequest request)
{
ubyte[] message = msgpack.pack(request);
ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof];
auto messageLength = message.length;
messageBuffer[0 .. size_t.sizeof] = (cast(ubyte*) &messageLength)[0 .. size_t.sizeof];
messageBuffer[size_t.sizeof .. $] = message[];
return socket.send(messageBuffer) == messageBuffer.length;
}
/**
* Gets the response from the server
*/
AutocompleteResponse getResponse(Socket socket)
{
ubyte[1024 * 16] buffer;
auto bytesReceived = socket.receive(buffer);
if (bytesReceived == Socket.ERROR)
throw new Exception("Incorrect number of bytes received");
if (bytesReceived == 0)
throw new Exception("Server closed the connection, 0 bytes received");
AutocompleteResponse response;
msgpack.unpack(buffer[0..bytesReceived], response);
return response;
}
void printDocResponse(AutocompleteResponse response) void printDocResponse(AutocompleteResponse response)
{ {
import std.array: join; import std.array: join;
response.docComments.join(r"\n\n").writeln; response.docComments.join(r"\n\n").writeln;
} }
void printLocationResponse(AutocompleteResponse response) void printLocationResponse(AutocompleteResponse response)

View File

@ -21,7 +21,7 @@ module common.dcd_version;
/** /**
* Human-readable version number * Human-readable version number
*/ */
enum DCD_VERSION = "v0.8.0-alpha1"; enum DCD_VERSION = "v0.8.0-beta2";
version (Windows) {} version (Windows) {}
else version (built_with_dub) {} else version (built_with_dub) {}

View File

@ -18,6 +18,9 @@
module common.messages; module common.messages;
import std.socket;
import msgpack;
/** /**
* The type of completion list being returned * The type of completion list being returned
*/ */
@ -157,3 +160,69 @@ struct AutocompleteResponse
*/ */
string[] importPaths; string[] importPaths;
} }
/**
* Returns: true on success
*/
bool sendRequest(Socket socket, AutocompleteRequest request)
{
ubyte[] message = msgpack.pack(request);
ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof];
auto messageLength = message.length;
messageBuffer[0 .. size_t.sizeof] = (cast(ubyte*) &messageLength)[0 .. size_t.sizeof];
messageBuffer[size_t.sizeof .. $] = message[];
return socket.send(messageBuffer) == messageBuffer.length;
}
/**
* Gets the response from the server
*/
AutocompleteResponse getResponse(Socket socket)
{
ubyte[1024 * 16] buffer;
auto bytesReceived = socket.receive(buffer);
if (bytesReceived == Socket.ERROR)
throw new Exception("Incorrect number of bytes received");
if (bytesReceived == 0)
throw new Exception("Server closed the connection, 0 bytes received");
AutocompleteResponse response;
msgpack.unpack(buffer[0..bytesReceived], response);
return response;
}
/**
* Returns: true if a server instance is running
* Params:
* useTCP = `true` to check a TCP port, `false` for UNIX domain socket
* socketFile = the file name for the UNIX domain socket
* port = the TCP port
*/
bool serverIsRunning(bool useTCP, string socketFile, ushort port)
{
scope (failure)
return false;
AutocompleteRequest request;
request.kind = RequestKind.query;
Socket socket;
scope (exit)
{
socket.shutdown(SocketShutdown.BOTH);
socket.close();
}
if (useTCP)
{
socket = new TcpSocket(AddressFamily.INET);
socket.connect(new InternetAddress("localhost", port));
}
else
{
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
socket.connect(new UnixAddress(socketFile));
}
socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5));
socket.blocking = true;
if (sendRequest(socket, request))
return getResponse(socket).completionType == "ack";
else
return false;
}

View File

@ -42,4 +42,8 @@ string generateSocketName()
"dcd.socket"); "dcd.socket");
} }
} }
else
{
assert(0);
}
} }

View File

@ -73,6 +73,8 @@ int main(string[] args)
string socketFile = generateSocketName(); string socketFile = generateSocketName();
} }
sharedLog.fatalHandler = () {};
try try
{ {
getopt(args, "port|p", &port, "I", &importPaths, "help|h", &help, getopt(args, "port|p", &port, "I", &importPaths, "help|h", &help,
@ -86,6 +88,8 @@ int main(string[] args)
return 1; return 1;
} }
globalLogLevel = level;
if (printVersion) if (printVersion)
{ {
version (Windows) version (Windows)
@ -109,7 +113,11 @@ int main(string[] args)
return 1; return 1;
} }
globalLogLevel = level; if (serverIsRunning(useTCP, socketFile, port))
{
fatal("Another instance of DCD-server is already running");
return 1;
}
info("Starting up..."); info("Starting up...");
StopWatch sw = StopWatch(AutoStart.yes); StopWatch sw = StopWatch(AutoStart.yes);
@ -128,17 +136,25 @@ int main(string[] args)
} }
else else
{ {
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); version(Windows)
if (exists(socketFile))
{ {
info("Cleaning up old socket file at ", socketFile); fatal("UNIX domain sockets not supported on Windows");
remove(socketFile); return 1;
}
else
{
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
if (exists(socketFile))
{
info("Cleaning up old socket file at ", socketFile);
remove(socketFile);
}
socket.blocking = true;
socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
socket.bind(new UnixAddress(socketFile));
setAttributes(socketFile, S_IRUSR | S_IWUSR);
info("Listening at ", socketFile);
} }
socket.blocking = true;
socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
socket.bind(new UnixAddress(socketFile));
setAttributes(socketFile, S_IRUSR | S_IWUSR);
info("Listening at ", socketFile);
} }
socket.listen(0); socket.listen(0);

View File

View File

@ -0,0 +1,9 @@
identifiers
C l
alignof k
i v
init k
mangleof k
sizeof k
stringof k
tupleof k

10
tests/tc027/file.d Normal file
View File

@ -0,0 +1,10 @@
struct Foo(C)
{
int i;
}
unittest
{
auto foo = Foo!int();
foo.
}

5
tests/tc027/run.sh Executable file
View File

@ -0,0 +1,5 @@
set -e
set -u
../../bin/dcd-client $1 file.d -c66 > actual1.txt
diff actual1.txt expected1.txt