.NET Rangers

I am proud to announce that the .NET Rangers community is back ! We have 3 MVP !

We have a blog : http://www.dotnetrangers.org and a Twitter account:

.NET Rangers @RangersNet

Members of the community:

  • Jean-Baptiste B. Sogeti
  • Cdric G. Sogeti
  • Jean-Nicolas B. Sogeti
  • Guilhem M. C-S
  • Cdric T. Sogeti
  • Keelan C. Sogeti
  • Eva D. Neos-SDI
  • Frederic S. Sydev
  • Michel F. Indep
  • Jean-Nol G. Indep
  • Christophe P. Neos-SDI
Advertisements

Article in Technical Magazine Programmez N° 219 – June 2018

May be in next June edition of french magazine Programmez, an article about creating a Windows Service. All the plumbing ! The second part will explain how to host a deamon inside and respond to external communication.

Creating the Ping feature for a middleware

For my clustering master/worker nodes, I have put a Ping thread:

To be production code, I will protect the vector _nodes. It’s a multi-thread appz so… it needs to be done.

void MyServer::ActivatePingThread()
{
	DWORD dwThreadId = 0;
	HANDLE hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &MyServer::PingThread, NULL, 0, &dwThreadId);
}

void MyServer::PingThread(LPVOID param)
{
	while (TRUE)
	{

		::Sleep(2000);

		std::shared_ptr<NodeAttributes> pObj = nullptr;

		for (auto itr = _nodes.begin(); itr != _nodes.end(); itr++)
		{
			pObj = *itr;

			TCHAR sz[255];
			_stprintf(sz, _T("http://%s:%s/MyServer/LMDB/"), pObj->_server.c_str(), pObj->_port.c_str());

			std::wstring address = sz;

			http_client client(address);

			std::wostringstream buf;
			buf << _T("?request=") << _T("ping");

			http_response response;

			try
			{
				wcout << _T("Ping testing ip:") << pObj->_server.c_str() << _T(" on port:") << pObj->_port.c_str() << endl;
				response = client.request(methods::GET, buf.str()).get();
				wcout << response.to_string() << endl;
			}
			catch (...)
			{
				// Something goes wrong !
				pObj->_isActive = false;
				*itr = pObj;
			}

			json::value jdata = json::value::array();
			jdata = response.extract_json().get();

			if (jdata.is_null())
			{
				std::wcout << _T("no JSON data...") << std::endl;

				// Something goes wrong !
				pObj->_isActive = false;
				*itr = pObj;
				continue;
			}

			PingData data = PingData::FromJSON(jdata.as_object());

			if (data.status == _T("OK"))
			{
				// Normal behaviour
			}
			else
			{
				// Something goes wrong !
				pObj->_isActive = false;
				*itr = pObj;
			}

			::Sleep(1000);
		}
	}
}

Creating a cluster of nodes in C++ REST

Creating a cluster of nodes…

I have a server appz that can be forked either to start nodes or the main server controller node.

When a node starts, its register with the node controller (master) giving its ip, its port and a name.

The node controller keeps that information in a std::vector<T>.

There is also an admin tool to send commands and see what’s in the master node.

start myserver

start myserver 192.168.1.33 7002 node node_1

start myserver 192.168.1.33 7003 node node_2

start myserver 192.168.1.33 7004 node node_3

start myclient 192.168.1.33 7001

The first myserver instance is the controller node (master). All others instances are worker nodes on a dedicated ip/port.

They all register with master. Master node will allow a node to be active when a client request for a node…

An admin tool allow to known when it happened:

F:DevGitHubLMDBLMDBWindowsx64Debug>admin 192.168.1.33 7001

Client http://192.168.1.33:7001/MyServer/LMDB/

Enter a command:?request=show-nodes

HTTP/1.1 200 OK

Content-Length: 0

Date: Sat, 19 May 2018 15:25:52 GMT

Server: Microsoft-HTTPAPI/2.0

Message GET /MyServer/LMDB/?request=show-nodes HTTP/1.1

Connection: Keep-Alive

Host: 192.168.1.33:7001

User-Agent: cpprestsdk/2.10.2

Relative URI /?request=show-nodes

Query request show-nodes

Request show-nodes

show-nodes…

Active:0 Server:192.168.1.33 Port:7002 Name:node_1

Active:0 Server:192.168.1.33 Port:7003 Name:node_2

Active:0 Server:192.168.1.33 Port:7004 Name:node_3

As we can see, there are registered nodes but no active one yet.

If I start a client asking for a worker node: myclient 192.168.1.33 7001

The server reacts:

Relative URI /?request=get-node&name=cache_v1

Query name cache_v1

Query request get-node

Request get-node

name cache_v1

get-node…

{"ip":"192.168.1.33","name":"cache_v1","port":"7002"}

If I ask my admin tool to show nodes:

Relative URI /?request=show-nodes

Query request show-nodes

Request show-nodes

show-nodes…

Active:1 Server:192.168.1.33 Port:7002 Name:cache_v1

Active:0 Server:192.168.1.33 Port:7003 Name:node_2

Active:0 Server:192.168.1.33 Port:7004 Name:node_3

There is one active node. The name is submitted by the client for an LMDB database names cache_v1.

.NET Ranger – The community is reborn !

I am proud to announce that the .Net Rangers are back !

The web site www.dotnetrangers.org is live.

We are a community of Windows Experts in development and infrastructure. Stay tuned !

Give the extra class for HTTP Server !

Here is the code :

 

#pragma once

class LMDBData
{
public:
	LMDBData();
	virtual ~LMDBData();

public:
	MDB_env * m_env;
	MDB_dbi m_dbi;
	MDB_txn * m_txn;
	MDB_val m_key;
	MDB_val m_data;
	MDB_stat m_mst;
};

#include "StdAfx.h"
#include "LMDBData.h"

LMDBData::LMDBData()
{
}

LMDBData::~LMDBData()
{
}

Give me the main of the HTTP Server

Here is the code :

#include "stdafx.h"
#include "MyServer.h"

using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;

std::unique_ptr<MyServer> g_http;


std::wstring GetIP()
{
	USES_CONVERSION;

	// Init WinSock
	WSADATA wsa_Data;
	int wsa_ReturnCode = WSAStartup(0x101, &wsa_Data);

	// Get the local hostname
	char szHostName[255];
	gethostname(szHostName, 255);
	struct hostent *host_entry;
	host_entry = gethostbyname(szHostName);
	char * szLocalIP;
	szLocalIP = inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list);
	WSACleanup();

	std::wstring ip = A2W(szLocalIP);
	return ip;
}

int wmain(int argc, wchar_t *argv[])
{
    utility::string_t port = U("7001");
	std::wstring defaultAddress = _T("localhost");
	if(argc == 2)
    {
        port = argv[1];
    }
	if (argc == 3)
	{
		defaultAddress = argv[1];
		port = argv[2];
	}

	std::wstring ip = GetIP();
	std::wcout << L"IP : " << ip << std::endl;

	std::wstring address = _T("http://");
	address.append(ip); // defaultAddress); //ip
	address.append(_T(":"));
	address.append(port);
	address.append(_T("/MyServer/LMDB/"));
	http::uri uri = http::uri(address);
	auto addr = uri.to_string();

	//
	// Create the server instance
	//

	std::wcout << L"Server " << addr << std::endl;

	g_http = std::unique_ptr<MyServer>(new MyServer(addr));
	g_http->Init_LMDB();
	g_http->open().wait();

	ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
	std::cout << "Press ENTER to exit." << std::endl;
    std::string line;
    std::getline(std::cin, line);

	g_http->close().wait();
	return 0;
}