Browse Source

D/Kiss: initial submit for benchmark test (#3695)

* D/Kiss: initial submit for benchmark test

* D/Kiss: Works with LDC 1.7.0

* The response should be generated dynamically
Heromyth 7 years ago
parent
commit
8dd5ad6809

+ 17 - 0
frameworks/D/kiss/README.md

@@ -0,0 +1,17 @@
+# Kiss Benchmarking Test
+
+This is the Kiss portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+
+## Requirements
+* Dlang > 2.079
+
+## Test URLs
+
+### JSON Encoding Test
+
+    http://localhost:8080/json
+    
+### PlanText Test
+
+    http://localhost:8080/plaintext

+ 43 - 0
frameworks/D/kiss/benchmark_config.json

@@ -0,0 +1,43 @@
+{
+  "framework": "kiss",
+  "tests": [{
+    "default": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "Kiss",
+      "language": "D",
+      "flavor": "DLang2",
+      "orm": "Raw",
+      "platform": "Kiss",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Kiss",
+      "notes": "",
+      "versus": "Kiss"
+  },
+    "ldc": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "Kiss",
+      "language": "D",
+      "flavor": "DLang2",
+      "orm": "Raw",
+      "platform": "Kiss",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Kiss",
+      "notes": "",
+      "versus": "Kiss"
+    }
+  }]
+}

+ 13 - 0
frameworks/D/kiss/dub.json

@@ -0,0 +1,13 @@
+{
+	"name": "kiss-benchmark",
+	"targetType": "executable",
+	"authors": [
+		"Putao"
+	],
+	"description": "A simple http server powered by KISS.",
+	"copyright": "Copyright © 2017-2018, HuntLabs.cn",
+	"license": "Apache-2.0",
+	"dependencies": {
+		"kiss" : "~>0.3.2"
+	}
+}

+ 9 - 0
frameworks/D/kiss/kiss-ldc.dockerfile

@@ -0,0 +1,9 @@
+FROM dlanguage/ldc:1.7.0
+
+ADD ./ /kiss
+WORKDIR /kiss
+
+RUN dub upgrade --verbose
+RUN dub build -f --arch=x86_64 --build=release --compiler=ldc2
+
+CMD ["./kiss-benchmark"]

+ 9 - 0
frameworks/D/kiss/kiss.dockerfile

@@ -0,0 +1,9 @@
+FROM dlanguage/ldc:1.7.0
+
+ADD ./ /kiss
+WORKDIR /kiss
+
+RUN dub upgrade --verbose
+RUN dub build -f --arch=x86_64 --build=release
+
+CMD ["./kiss-benchmark"]

+ 220 - 0
frameworks/D/kiss/source/app.d

@@ -0,0 +1,220 @@
+/*
+ * Collie - An asynchronous event-driven network framework using Dlang development
+ *
+ * Copyright (C) 2015-2018  Shanghai Putao Technology Co., Ltd 
+ *
+ * Developer: putao's Dlang team
+ *
+ * Licensed under the Apache-2.0 License.
+ *
+ */
+import std.stdio;
+
+import kiss.event;
+import kiss.net;
+import kiss.util.thread;
+
+import std.array;
+import std.conv;
+import std.json;
+import std.functional;
+import std.getopt;
+import std.exception;
+import std.datetime;
+import std.parallelism;
+import std.socket;
+import std.string;
+
+/**
+*/
+abstract class AbstractTcpServer
+{
+	protected EventLoopGroup _group = null;
+	protected bool _isStarted = false;
+	protected Address _address;
+
+	this(Address address, int thread = (totalCPUs - 1))
+	{
+		this._address = address;
+		_group = new EventLoopGroup(cast(uint) thread);
+	}
+
+	@property Address bindingAddress()
+	{
+		return _address;
+	}
+
+	void start()
+	{
+		if (_isStarted)
+			return;
+
+		for (size_t i = 0; i < _group.length; ++i)
+			createServer(_group[i]);
+		_group.start();
+		_isStarted = true;
+	}
+
+	protected void createServer(EventLoop loop)
+	{
+		TcpListener listener = new TcpListener(loop, _address.addressFamily);
+
+		listener.reusePort(true);
+		listener.bind(_address).listen(1024);
+		listener.acceptHandler = &onConnectionAccepted;
+		listener.start();
+	}
+
+	protected void onConnectionAccepted(TcpListener sender, TcpStream client);
+
+	void stop()
+	{
+		if (!_isStarted)
+			return;
+		_isStarted = false;
+		_group.stop();
+	}
+}
+
+/**
+*/
+class HttpServer : AbstractTcpServer
+{
+	this(string ip, ushort port, int thread = (totalCPUs - 1))
+	{
+		super(new InternetAddress(ip, port), thread);
+	}
+
+	this(Address address, int thread = (totalCPUs - 1))
+	{
+		super(address, thread);
+	}
+
+	override protected void onConnectionAccepted(TcpListener sender, TcpStream client)
+	{
+		client.onDataReceived((in ubyte[] data) {
+			handleReceivedData(client, data);
+		}).onClosed(() { notifyClientClosed(client); }).onError((string msg) {
+			writeln("Error: ", msg);
+		});
+	}
+
+	protected void handleReceivedData(TcpStream client, in ubyte[] data)
+	{
+		string request = cast(string) data;
+		bool keepAlive = indexOf(request, " keep-alive", CaseSensitive.no) > 0;
+
+		ptrdiff_t index = indexOf(request, "/plaintext ", CaseSensitive.no);
+		if (index > 0)
+			respondPlaintext(client, keepAlive);
+		else if (indexOf(request, "/json ", CaseSensitive.no) > 0)
+		{
+			respondJson(client, keepAlive);
+		}
+		else
+		{
+			badRequest(client);
+		}
+
+	}
+
+	private void respondPlaintext(TcpStream client, bool keepAlive)
+	{
+		string content = "Hello, World!";
+		Appender!string sb;
+		sb.put("HTTP/1.1 200 OK");
+		sb.put("\r\n");
+		sb.put("Server: Kiss/0.3");
+		sb.put("\r\n");
+		sb.put("Connection: Keep-Alive");
+		sb.put("\r\n");
+		sb.put("Content-Type: text/plain");
+		sb.put("\r\n");
+		sb.put("Content-Length: " ~ to!string(content.length));
+		sb.put("\r\n");
+		sb.put("Date: " ~ Clock.currTime.toString());
+		sb.put("\r\n\r\n");
+		sb.put(content);
+
+		client.write(cast(ubyte[]) sb.data, (in ubyte[], size_t) {
+			if (!keepAlive)
+				client.close();
+		});
+	}
+
+	private void respondJson(TcpStream client, bool keepAlive)
+	{
+		JSONValue js;
+		js["message"] = "Hello, World!";
+		string content = js.toString();
+
+		Appender!string sb;
+		sb.put("HTTP/1.1 200 OK");
+		sb.put("\r\n");
+		sb.put("Server: Kiss/0.3");
+		sb.put("\r\n");
+		sb.put("Connection: Keep-Alive");
+		sb.put("\r\n");
+		sb.put("Content-Type: application/json");
+		sb.put("\r\n");
+		sb.put("Content-Length: " ~ to!string(content.length));
+		sb.put("\r\n");
+		sb.put("Date: " ~ Clock.currTime.toString());
+		sb.put("\r\n\r\n");
+		sb.put(content);
+
+		client.write(cast(ubyte[]) sb.data, (in ubyte[], size_t) {
+			if (!keepAlive)
+				client.close();
+		});
+	}
+
+	private void badRequest(TcpStream client)
+	{
+		string content = `<html>
+<head><title>404 Not Found</title></head>
+<body bgcolor="white">
+<center><h1>404 Not Found</h1></center>
+<hr><center>Kiss/0.3</center>
+</body>
+</html>`;
+		Appender!string sb;
+		sb.put("HTTP/1.1 404 Not Found");
+		sb.put("\r\n");
+		sb.put("Server: Kiss/0.3");
+		sb.put("\r\n");
+		sb.put("Connection: keep-alive");
+		sb.put("\r\n");
+		sb.put("Content-Type: text/html");
+		sb.put("\r\n");
+		sb.put("Content-Length: " ~ to!string(content.length));
+		sb.put("\r\n");
+		sb.put("Date: " ~ Clock.currTime.toString());
+		sb.put("\r\n\r\n");
+		sb.put(content);
+
+		client.write(cast(ubyte[]) sb.data);
+		client.close();
+	}
+
+	protected void notifyClientClosed(TcpStream client)
+	{
+		debug writefln("The connection[%s] is closed on thread %s",
+				client.remoteAddress(), getTid());
+	}
+}
+
+void main(string[] args)
+{
+	ushort port = 8080;
+	GetoptResult o = getopt(args, "port|p", "Port (default 8080)", &port);
+	if (o.helpWanted)
+	{
+		defaultGetoptPrinter("A simple http server powered by KISS!", o.options);
+		return;
+	}
+
+	HttpServer httpServer = new HttpServer("0.0.0.0", 8080, totalCPUs);
+	writefln("listening on %s", httpServer.bindingAddress.toString());
+	httpServer.start();
+}