.. index:: 
	single: RingLibuv; Introduction

===============
Using RingLibuv
===============

In this chapter we will learn about using RingLibuv

.. note:: To use RingLibuv, Check ring/extensions/ringlibuv folder.

Information from the library website: http://libuv.org/

Libuv is a multi-platform support library with a focus on asynchronous I/O. 

Feature highlights

* Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
* Asynchronous TCP and UDP sockets
* Asynchronous DNS resolution
* Asynchronous file and file system operations
* File system events
* ANSI escape code controlled TTY
* IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
* Child processes
* Thread pool
* Signal handling
* High resolution clock
* Threading and synchronization primitives

.. index:: 
	pair: RingLibuv; First Application using RingLibuv

First Application using RingLibuv
=================================

Example:

.. code-block:: ring

	load "libuv.ring"

	func main

		myloop = new_uv_loop_t()
		uv_loop_init(myloop)
		? "Now quitting"
		uv_run(myloop, UV_RUN_DEFAULT)
		uv_loop_close(myloop)
		destroy_uv_loop_t(myloop)

Output:

.. code-block:: none

	Now quitting


.. index:: 
	pair: RingLibuv; The Events Loop

The Events Loop
===============

Example:

.. code-block:: ring

	load "libuv.ring"

	counter = 0
	idler = NULL 

	func main
		idler = new_uv_idle_t()
		uv_idle_init(uv_default_loop(), idler)
		uv_idle_start(idler, "wait()")
		? "Idling..."
		uv_run(uv_default_loop(), UV_RUN_DEFAULT);
		uv_loop_close(uv_default_loop());
		destroy_uv_idle_t(idler)

	func wait
		counter++
		if counter >= 100000
			uv_idle_stop(idler)
		ok

Output:

.. code-block:: none

	Idling...

.. index:: 
	pair: RingLibuv; Server Example

Server Example
==============

Example:

.. code-block:: ring

	load "libuv.ring"

	? "Testing RingLibuv - Server Side"

	DEFAULT_PORT    = 13370
	DEFAULT_BACKLOG = 1024

	addr    = new_sockaddr_in()
	server  = NULL
	client  = NULL
	myloop  = NULL

	func main
		myloop = uv_default_loop()
		server = new_uv_tcp_t()
		uv_tcp_init(myloop, server)
		uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
		uv_tcp_bind(server, addr, 0)
		r = uv_listen(server, DEFAULT_BACKLOG, "newconnection()")
		if r 
			? "Listen error " + uv_strerror(r)
			return 1
		ok
		uv_run(myloop, UV_RUN_DEFAULT)
		destroy_uv_tcp_t(server)
		destroy_uv_sockaddr_in(addr)

	func newconnection
		? "New Connection"
		aPara   = uv_Eventpara(server,:connect)
		nStatus = aPara[2]
		if nStatus < 0
			? "New connection error : " + nStatus 
			return 
		ok
		client = new_uv_tcp_t()
		uv_tcp_init(myloop, client)
		if uv_accept(server, client) = 0 
				uv_read_start(client, uv_myalloccallback(), "echo_read()")
		ok

	func echo_read 
		aPara = uv_Eventpara(client,:read)
		nRead = aPara[2]
		buf   = aPara[3]
		if nRead > 0
			req = new_uv_write_t()
				wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread)
			uv_write(req, client, wrbuf, 1, "echo_write()")
			? uv_buf2str(wrbuf)
			message = "message from the server to the client"
			buf = new_uv_buf_t()
			set_uv_buf_t_len(buf,len(message))
			set_uv_buf_t_base(buf,varptr("message","char *"))
			uv_write(req, client, buf, 1, "echo_write()")
		ok

	func echo_write
		aPara = uv_Eventpara(client,:read)
		req   = aPara[1]

Output:

When we run the client, We will see the message "New Connection"

Then the message "hello from the client"

.. code-block:: none

	Testing RingLibuv - Server Side
	New Connection
	hello from the client

.. index:: 
	pair: RingLibuv; Client Example

Client Example
==============

Example:

.. code-block:: ring

	load "libuv.ring"

	? "Testing RingLibuv - Client Side"

	DEFAULT_PORT    = 13370
	DEFAULT_BACKLOG = 1024

	addr    = new_sockaddr_in()
	connect = NULL
	buffer  = null
	socket  = null

	func main
		myloop  = uv_default_loop()
		Socket  = new_uv_tcp_t()
		connect = new_uv_connect_t()
		uv_tcp_init(myloop, Socket)
		uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
		uv_tcp_connect(connect,Socket, addr, "connect()")
		uv_run(myloop, UV_RUN_DEFAULT)
		destroy_uv_tcp_t(socket)
		destroy_uv_connect_t(connect)

	func connect 
		? "Client: Start Connection"
		aPara   = uv_Eventpara(connect,:connect)
		req     = aPara[1]
		nStatus = aPara[2]
		if nStatus = -1
			? "Error : on_write_end "
			return 
		ok
		buf = new_uv_buf_t()
		message = "hello from the client"
		set_uv_buf_t_len(buf,len(message))
		set_uv_buf_t_base(buf,varptr("message","char *"))
		tcp       = get_uv_connect_t_handle(req)
		write_req = new_uv_write_t()
		buf_count = 1
		uv_write(write_req, tcp, buf, buf_count, "on_write_end()")

	func on_write_end
			uv_read_start(socket, uv_myalloccallback(), "echo_read()")

	func echo_read 
		aPara = uv_Eventpara(socket,:read)
		nRead = aPara[2]
		buf   = aPara[3]
		if nRead > 0
				wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread);
			? uv_buf2str(wrbuf)
		ok

Output:

We will run the client after the server

.. code-block:: none

	Testing RingLibuv - Client Side
	Client: Start Connection
	hello from the client
	message from the server to the client

.. index:: 
	pair: RingLibuv; Server Example using Classes

Server Example Using Classes
============================

Example:

.. code-block:: ring

	load "libuv.ring"
	load "objectslib.ring"

	? "Testing RingLibuv - Server Side - Using Classes"

	open_object(:MyServer)

	class MyServer from ObjectControllerParent

		DEFAULT_PORT    = 13370
		DEFAULT_BACKLOG = 1024
		
		addr    = new_sockaddr_in()
		server  = NULL
		client  = NULL
		myloop  = NULL
		
		func start
			myloop = uv_default_loop()
			server = new_uv_tcp_t()
			uv_tcp_init(myloop, server)
			uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
			uv_tcp_bind(server, addr, 0)
			r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) )
			if r 
				? "Listen error " + uv_strerror(r)
				return 1
			ok
			uv_run(myloop, UV_RUN_DEFAULT)
			destroy_uv_tcp_t(server)
			destroy_uv_sockaddr_in(addr)
		
		func newconnection
			? "New Connection"
			aPara   = uv_Eventpara(server,:connect)
			nStatus = aPara[2]
			if nStatus < 0
				? "New connection error : " + nStatus 
				return 
			ok
			client = new_uv_tcp_t()
			uv_tcp_init(myloop, client)
			if uv_accept(server, client) = 0 
					uv_read_start(client, uv_myalloccallback(), 
								Method(:echo_read))
			ok
		
		func echo_read 
			aPara = uv_Eventpara(client,:read)
			nRead = aPara[2]
			buf   = aPara[3]
			if nRead > 0
				req = new_uv_write_t()
					wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread)
				uv_write(req, client, wrbuf, 1, Method(:echo_write))
				? uv_buf2str(wrbuf)
				message = "message from the server to the client"
				buf = new_uv_buf_t()
				set_uv_buf_t_len(buf,len(message))
				set_uv_buf_t_base(buf,varptr("message","char *"))
				uv_write(req, client, buf, 1, Method(:echo_write))
			ok
		
		func echo_write
			aPara = uv_Eventpara(client,:read)
			req   = aPara[1]
	

Output:

When we run the client, We will see the message "New Connection"

Then the message "hello from the client"

.. code-block:: none

	Testing RingLibuv - Server Side - Using Classes
	New Connection
	hello from the client


.. index:: 
	pair: RingLibuv; Client Example - Using Classes

Client Example Using Classes
============================

Example:

.. code-block:: ring

	load "libuv.ring"
	load "objectslib.ring"

	? "Testing RingLibuv - Client Side - Using Classes"

	open_object(:MyClient)

	Class MyClient from ObjectControllerParent

		DEFAULT_PORT    = 13370
		DEFAULT_BACKLOG = 1024
		
		addr    = new_sockaddr_in()
		connect = NULL
		buffer  = null
		socket  = null
		
		func start
			myloop  = uv_default_loop()
			Socket  = new_uv_tcp_t()
			connect = new_uv_connect_t()
			uv_tcp_init(myloop, Socket)
			uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
			uv_tcp_connect(connect,Socket, addr, Method(:connect))
			uv_run(myloop, UV_RUN_DEFAULT)
			destroy_uv_tcp_t(socket)
			destroy_uv_connect_t(connect)
		
		func connect 
			? "Client: Start Connection"
			aPara   = uv_Eventpara(connect,:connect)
			req     = aPara[1]
			nStatus = aPara[2]
			if nStatus = -1
				? "Error : on_write_end "
				return 
			ok
			buf = new_uv_buf_t()
			message = "hello from the client"
			set_uv_buf_t_len(buf,len(message))
			set_uv_buf_t_base(buf,varptr("message","char *"))
			tcp       = get_uv_connect_t_handle(req)
			write_req = new_uv_write_t()
			buf_count = 1
			uv_write(write_req, tcp, buf, buf_count, Method(:on_write_end))
		
		func on_write_end
				uv_read_start(socket, uv_myalloccallback(), Method(:echo_read))
		
		func echo_read 
			aPara = uv_Eventpara(socket,:read)
			nRead = aPara[2]
			buf   = aPara[3]
			if nRead > 0
					wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread);
				? uv_buf2str(wrbuf)
			ok

Output:

We will run the client after the server

.. code-block:: none

	Testing RingLibuv - Client Side - Using Classes
	Client: Start Connection
	hello from the client
	message from the server to the client


	

.. index:: 
	pair: RingLibuv; Threads Example

Threads Example
===============

Example:

.. code-block:: ring

	load "libuv.ring"

	? "Testing RingLibuv - Threads"

	func main
		one_id = new_uv_thread_t()
		two_id = new_uv_thread_t()
		uv_thread_create(one_id, "one()")
		uv_thread_create(two_id, "two()")
		uv_thread_join(one_id)
		uv_thread_join(two_id)
		destroy_uv_thread_t(one_id)
		destroy_uv_thread_t(two_id)

	func one
		? "Message from the First Thread!"

	func two
		? "Message from the Second Thread!"

Output:

.. code-block:: none

	Testing RingLibuv - Threads
	Message from the First Thread!
	Message from the Second Thread!
    

.. index:: 
	pair: RingLibuv; Threads Example - Using Classes

Threads Example - Using Classes
===============================

Example:

.. code-block:: ring

	load "libuv.ring"
	load "objectslib.ring"

	? "Testing RingLibuv - Threads - Using Classes"

	open_object(:MyThreads)

	class MyThreads from ObjectControllerParent

		func Start
			one_id = new_uv_thread_t()
			two_id = new_uv_thread_t()
			uv_thread_create(one_id, Method(:One))
			uv_thread_create(two_id, Method(:Two))
			uv_thread_join(one_id)
			uv_thread_join(two_id)
			destroy_uv_thread_t(one_id)
			destroy_uv_thread_t(two_id)
		
		func one
			? "Message from the First Thread!"
		
		func Two
			? "Message from the Second Thread!"
		

Output:

.. code-block:: none

	Testing RingLibuv - Threads - Using Classes
	Message from the First Thread!
	Message from the Second Thread!

