1 module dls.server; 2 3 import dls.protocol.handlers; 4 import dls.protocol.jsonrpc; 5 6 shared static this() 7 { 8 import std.algorithm : map; 9 import std.array : join, split; 10 import std.meta : AliasSeq; 11 import std.traits : hasUDA, select; 12 import std.typecons : tuple; 13 import std.string : capitalize; 14 15 foreach (modName; AliasSeq!("general", "client", "text_document", "window", "workspace")) 16 { 17 mixin("import dls.protocol.messages" ~ (modName.length ? "." ~ modName : "") ~ ";"); 18 mixin("alias mod = dls.protocol.messages" ~ (modName.length ? "." ~ modName : "") ~ ";"); 19 20 foreach (thing; __traits(allMembers, mod)) 21 { 22 mixin("alias t = " ~ thing ~ ";"); 23 24 static if (isHandler!t) 25 { 26 enum attrs = tuple(__traits(getAttributes, t)); 27 enum attrsWithDefaults = tuple(modName[0] ~ modName.split('_') 28 .map!capitalize().join()[1 .. $], thing, attrs.expand); 29 enum parts = tuple(attrsWithDefaults[attrs.length > 0 ? 2 : 0], 30 attrsWithDefaults[attrs.length > 1 ? 3 : 1]); 31 enum method = select!(parts[0].length != 0)(parts[0] ~ "/", "") ~ parts[1]; 32 33 pushHandler(method, &t); 34 } 35 } 36 } 37 } 38 39 abstract class Server 40 { 41 import dls.protocol.interfaces : InitializeParams; 42 import dls.util.logger : logger; 43 import std.algorithm : find, findSplit; 44 import std.json : JSONValue; 45 import std.string : strip, stripRight; 46 import std.typecons : Nullable, nullable; 47 48 static bool initialized = false; 49 static bool shutdown = false; 50 static bool exit = false; 51 private static InitializeParams _initState; 52 53 @property static InitializeParams initState() 54 { 55 return _initState; 56 } 57 58 @property static void initState(InitializeParams params) 59 { 60 _initState = params; 61 62 debug 63 { 64 logger.trace = InitializeParams.Trace.verbose; 65 } 66 else 67 { 68 logger.trace = params.trace; 69 } 70 } 71 72 @property static InitializeParams.InitializationOptions initOptions() 73 { 74 return _initState.initializationOptions.isNull 75 ? new InitializeParams.InitializationOptions() : _initState.initializationOptions; 76 } 77 78 static void loop() 79 { 80 import std.conv : to; 81 import std.stdio : stdin; 82 83 while (!stdin.eof && !exit) 84 { 85 string[][] headers; 86 string line; 87 88 do 89 { 90 line = stdin.readln().stripRight(); 91 auto parts = line.findSplit(":"); 92 93 if (parts[1].length > 0) 94 { 95 headers ~= [parts[0], parts[2]]; 96 } 97 } 98 while (line.length > 0); 99 100 if (headers.length == 0) 101 { 102 continue; 103 } 104 105 auto contentLengthResult = headers.find!((parts, 106 name) => parts.length > 0 && parts[0] == name)("Content-Length"); 107 108 if (contentLengthResult.length == 0) 109 { 110 logger.error("No valid Content-Length section in header"); 111 continue; 112 } 113 114 static char[] buffer; 115 const contentLength = contentLengthResult[0][1].strip().to!size_t; 116 buffer.length = contentLength; 117 const content = stdin.rawRead(buffer); 118 119 handleJSON(content); 120 } 121 } 122 123 private static void handleJSON(in char[] content) 124 { 125 import dls.protocol.jsonrpc : send, sendError; 126 import dls.util.json : convertFromJSON; 127 import std.algorithm : canFind; 128 import std.json : JSONException, parseJSON; 129 130 RequestMessage request; 131 132 try 133 { 134 const json = parseJSON(content); 135 136 if ("method" in json) 137 { 138 if ("id" in json) 139 { 140 request = convertFromJSON!RequestMessage(json); 141 142 if (!shutdown && (initialized || ["initialize"].canFind(request.method))) 143 { 144 send(request.id, handler!RequestHandler(request.method)(request.params)); 145 } 146 else 147 { 148 sendError(ErrorCodes.serverNotInitialized, request, JSONValue()); 149 } 150 } 151 else 152 { 153 auto notification = convertFromJSON!NotificationMessage(json); 154 155 if (initialized) 156 { 157 handler!NotificationHandler(notification.method)(notification.params); 158 } 159 } 160 } 161 else 162 { 163 auto response = convertFromJSON!ResponseMessage(json); 164 165 if (response.error.isNull) 166 { 167 handler!ResponseHandler(response.id.str)(response.id.str, response.result); 168 } 169 else 170 { 171 logger.error(response.error.message); 172 } 173 } 174 } 175 catch (JSONException e) 176 { 177 logger.errorf("%s: %s", ErrorCodes.parseError[0], e); 178 sendError(ErrorCodes.parseError, request, JSONValue(e.message)); 179 } 180 catch (HandlerNotFoundException e) 181 { 182 logger.errorf("%s: %s", ErrorCodes.methodNotFound[0], e); 183 sendError(ErrorCodes.methodNotFound, request, JSONValue(e.message)); 184 } 185 catch (Exception e) 186 { 187 logger.errorf("%s: %s", ErrorCodes.internalError[0], e); 188 sendError(ErrorCodes.internalError, request, JSONValue(e.message)); 189 } 190 } 191 }