예제 #1
0
 void sendTextFrame(WebSocket& ws, const std::string& s)
 {
     ws.sendFrame(s.data(), s.size());
 }
예제 #2
0
int main()
{
	AutoPtr<XMLConfiguration> pConf(new XMLConfiguration("settings.xml")); // instantiating the XMLConfiguration and reading from setting.xml

	char buffer[2048];
	memset(buffer, 0, sizeof buffer);
	int flags;
	int n;
	string payload;
	string out;
	int msg_cnt = 0;

	pthread_t fifoReadThread;	//indivudual thread for fifo so it doesn't block other stuff
	int iret1 = pthread_create(&fifoReadThread, NULL, CreatePiSocketFifo, NULL);




	//variables to be set in xml config file //
	string signalr_service_url = pConf->getString("signalr_url"); 
	string signalr_url_endpoint = pConf->getString("signalr_url_endpoint");
	int signalr_service_port = pConf->getInt("signalr_port");
	int timeout_seconds = pConf->getInt("timeout");
	string api_endpoint_url = pConf->getString("api_endpoint_url"); // ""
	//pipe_from_main = pConf->getString("pipe_from_main");
	//string pipe_from_socket = pConf->getString("pipe_from_socket");

	//--------------------------------------//

	//cout << endl << "=============================================================" << endl;
	//cout << "api_endpoint_url -> " << api_endpoint_url << endl;
	//cout << "signalr_url_endpoint -> " << signalr_url_endpoint << endl;
	//cout << "signalr_service_port -> " << signalr_service_port << endl;
	//cout << "timeout_seconds -> " << timeout_seconds << endl;
	//cout << "api_endpoint_url -> " << api_endpoint_url << endl;
	//cout << "pipe_from_main -> " << pipe_from_main;
	//cout << endl << "=============================================================" << endl << endl;

	//cout << "Opening pipe: " << pipe_from_main << endl;

	//fd = open(pipe_from_main.c_str(), O_WRONLY); // open pipe as readonly
	//write(fd, "Hello World", sizeof("Hello World"));
	//close(fd);

conn:	//label for the goto's in the catches 
	try{
		time_t seconds_past_epoch = time(0);
		cout << "STARTING " << endl;

		char port[100];
		char id[100];
		snprintf(port, sizeof(port), "%d", signalr_service_port); // converting int variables to char[]
		snprintf(id, sizeof(id), "%ld", (seconds_past_epoch * 1000)); // converting int variables to char[]


		string my_mac = getMACC(); //Get the mac address

		//compose the URI for getting the token
		URI uri("http://" + signalr_service_url + ":" + port + "/" + signalr_url_endpoint + "/negotiate?_" + id + "&UID=" + my_mac);
		HTTPClientSession session(uri.getHost(), uri.getPort()); // instantiating a client session
		//if there is a network problem between Pi and SignalR everything will break and the catch will point back to the goto label
		//we set this in order to a lower minimise the retry period thus the downtime 
		session.setTimeout(timeout_seconds * 1e+6); // time in microseconds; 
		string path(uri.getPathAndQuery());

		// send the request
		HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
		session.sendRequest(req);


		StringTokenizer tokenizer(session.socket().address().toString(), ":", StringTokenizer::TOK_TRIM); // get the request originating address:ip from the session socket initiated by HTPP; tokenize it for IP extraction
		//string my_mac = getMAC((tokenizer[0]).c_str()); // call IP to MAC converter

		


		// get response
		HTTPResponse res;
		istream& is = session.receiveResponse(res); // stream the request
		cout << res.getStatus() << " " << res.getReason() << endl; // get the status code of the transaction

		// convert the istream to sting for further processing
		istreambuf_iterator<char> eos;
		string s(istreambuf_iterator<char>(is), eos);

		const char * cc = s.c_str();
		// instantiate a rapidjson document and fill it up with the response of the negotiation request
		rapidjson::Document document; 
		document.Parse<0>(cc); 
		string token = document["ConnectionToken"].GetString(); // parse the response and get the connectionToken

		//=============================================

		//connect to signarR using the connectionToken got previously
		HTTPClientSession cs(signalr_service_url, signalr_service_port); // instantiate simple webclient
		string what = "/" + signalr_url_endpoint + "/connect?transport=webSockets&connectionToken=" + urlencode(token) + "&UID=" + my_mac + "&connectionData=%5B%7B%22name%22%3A%22myhub%22%7D%5D&tid=10"; // compose the request string
		HTTPRequest request(HTTPRequest::HTTP_GET, what, "HTTP/1.1"); // the protocol MUST be HTTP/1.1, as described in RFC6455; else the UPGRADE to websocket request will fail
		request.set("Host", signalr_service_url); // specify the Host header to be sent
		HTTPResponse response; // instantiate a http response
		cout << response.getStatus() << " " << response.getReason() << endl;
		WebSocket * ws = new WebSocket(cs, request, response); // instantiate a WebSocket transaction to the 'cs' session, sending the 'request' and storing the 'response'

		//sample of a message to be sent
		payload = "{\"H\":\"myhub\",\"M\":\"Send\",\"A\":[\"" + my_mac + "\",\"invoked from " + replaceInPlace(my_mac, std::string(":"), std::string("-")) + " client\"],\"I\":0}";
		// cout << endl << payload << endl ;
		ws->sendFrame(payload.data(), payload.size(), WebSocket::FRAME_TEXT); // send the message to signalR using the payload and setting the type of frame to be sent as FRAME_TEXT

		flags = 1;
		// starting the receiving loop
		while( (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE ) // while websocket session open
		{
			n = ws->receiveFrame(buffer, sizeof(buffer), flags); // n is the received frame
			// flags store the response flags of the frame
			// 129 = single frame response
			// 1   = start of multi-frame response
			// 0   = continuation frame of a multi-frame response
			// 128 = FIN frame os a multi-frame response

			// signalR send data in JSON format, and it send empty messages (empty json document) on a regular basis

			if( (n != 2) && flags !=1 ) // filter out empty jsons and multiframe responses (multiframe will be treated further on)
			{
				cout << "RCV[" << msg_cnt << "]=>	" << buffer << " ===== " << unsigned(flags) << endl;
			}

			if(flags == 1){ // if I get a start frame of a multi-frame response means that I am getting something usefull from signalR
				string str(buffer);
				out += str;
				// due to flag == 1, we are expecting several frames, until we got flag == 128
				do{
					n = ws->receiveFrame(buffer, sizeof(buffer), flags);
					string str(buffer);
					out += str; // we add the next frame/frames to the out variable, to construct the whole JSON message
					str = "";
					memset(buffer, 0, sizeof buffer); // be sure to empty the buffer to don't end up with junk
				}while(flags != 128);
				cout << endl << "=> " << out << endl;

				//not as we got a valid response from signalR endpoint, lets process it

				//convert the out variable and pass is as a Document to the JSON parser
				const char * c = out.c_str();
				rapidjson::Document document;
				document.Parse<0>(c);
				out = document["M"][rapidjson::SizeType(0)]["A"][rapidjson::SizeType(1)].GetString(); // get out only the actual sent message from the response message


				SendMessageToMain(out.c_str());


				cout << "Msg Received";

				message_action(api_endpoint_url,out); // do something with the message in the message_action function
				out = "";
			}
			msg_cnt++;
			memset(buffer, 0, sizeof buffer); // we always cleanup
		}
		ws->shutdown();
	}
	// if something goes wrong with the connection, we try to recover
	catch (WebSocketException& exc0)
	{
		cout <<"WebSocketException "<< exc0.displayText() << endl;
	}
	catch (Poco::TimeoutException& exc1) // handle webclient errors 
	{
		goto conn; // lets try again from the top
		cout <<"TimeoutException "<< exc1.displayText() << endl;
		// return 1;
	}
	catch (ConnectionResetException& exc) // handle connec errors
	{
		goto conn; // lets try again from the top
		cout << "!!!ConnectionResetException:" << exc.displayText() << endl;
		// return 1;
	}
	cout << strerror(errno) << endl;
	return 0;
}