<commit_before># This file is part of NIT (http://www.nitlanguage.org).
#
# Copyright 2013 <NAME> <<EMAIL>>
# Copyright 2014 <NAME> <<EMAIL>>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Low-level wrapper around the libevent library to manage events on file descriptors
#
# For mor information, refer to the libevent documentation at
# http://monkey.org/~provos/libevent/doxygen-2.0.1/
module libevent is pkgconfig("libevent")

in "C header" `{
	#include <sys/stat.h>
	#include <sys/types.h>
	#include <fcntl.h>
	#include <errno.h>
	#include <sys/socket.h>

	#include <event2/listener.h>
	#include <event2/bufferevent.h>
	#include <event2/buffer.h>
`}

in "C" `{
	// Callback forwarded to 'Connection.write_callback'
	static void c_write_cb(struct bufferevent *bev, Connection ctx) {
		Connection_write_callback(ctx);
	}

	// Callback forwarded to 'Connection.read_callback_native'
	static void c_read_cb(struct bufferevent *bev, Connection ctx)
	{
		// TODO move to Nit code
		struct evbuffer *input = bufferevent_get_input(bev);
		size_t len = evbuffer_get_length(input);
		char* cstr = malloc(len);
		evbuffer_remove(input, cstr, len);
		Connection_read_callback_native(ctx, cstr, len);
	}

	// Callback forwarded to 'Connection.event_callback'
	static void c_event_cb(struct bufferevent *bev, short events, Connection ctx)
	{
		Connection_event_callback(ctx, events);

		// TODO move to Nit code
		if (events & BEV_EVENT_ERROR)
			perror("Error from bufferevent");
		if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
			bufferevent_free(bev);
			Connection_decr_ref(ctx);
		}
	}

	// Callback fowarded to 'ConnectionFactory.spawn_connection'
	static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd,
		struct sockaddr *address, int socklen, ConnectionFactory ctx)
	{
		// TODO move to Nit code
		struct event_base *base = evconnlistener_get_base(listener);
		struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

		Connection nit_con = ConnectionFactory_spawn_connection(ctx, bev);
		Connection_incr_ref(nit_con);

		bufferevent_setcb(bev,
			(bufferevent_data_cb)c_read_cb,
			(bufferevent_data_cb)c_write_cb,
			(bufferevent_event_cb)c_event_cb, nit_con);
		bufferevent_enable(bev, EV_READ|EV_WRITE);
	}
`}

# Structure to hold information and state for a Libevent dispatch loop.
#
# The event_base lies at the center of Libevent; every application will
# have one.  It keeps track of all pending and active events, and
# notifies your application of the active ones.
extern class NativeEventBase `{ struct event_base * `}

	# Create a new event_base to use with the rest of Libevent
	new `{ return event_base_new(); `}

	# Has `self` been correctly initialized?
	fun is_valid: Bool do return not address_is_null

	# Event dispatching loop
	#
	# This loop will run the event base until either there are no more added
	# events, or until something calls `exit_loop`.
	fun dispatch `{ event_base_dispatch(self); `}

	# Exit the event loop
	#
	# TODO support timer
	fun exit_loop `{ event_base_loopexit(self, NULL); `}

	# Destroy this instance
	fun destroy `{ event_base_free(self); `}
end

# Spawned to manage a specific connection
#
# TODO, use polls
class Connection
	super Writer

	# Closing this connection has been requested, but may not yet be `closed`
	var close_requested = false

	# This connection is closed
	var closed = false

	# The native libevent linked to `self`
	var native_buffer_event: NativeBufferEvent

	# Close this connection if possible, otherwise mark it to be closed later
	redef fun close
	do
		if closed then return
		var success = native_buffer_event.destroy
		close_requested = true
		closed = success
	end

	# Callback method on a write event
	fun write_callback
	do
		if close_requested and not closed then close
	end

	private fun read_callback_native(cstr: NativeString, len: Int)
	do
		read_callback(cstr.to_s_with_length(len))
	end

	# Callback method when data is available to read
	fun read_callback(content: String)
	do
		if close_requested and not closed then close
	end

	# Callback method on events
	fun event_callback(events: Int) do end

	# Write a string to the connection
	redef fun write(str)
	do
		if close_requested then return
		native_buffer_event.write(str.to_cstring, str.bytelen)
	end

	redef fun write_byte(byte)
	do
		if close_requested then return
		native_buffer_event.write_byte(byte)
	end

	redef fun write_bytes(bytes)
	do
		if close_requested then return
		native_buffer_event.write(bytes.items, bytes.length)
	end

	# Write a file to the connection
	#
	# If `not path.file_exists`, the method returns.<commit_msg>lib/libevent: remove duplicated check on `closed`<commit_after># This file is part of NIT (http://www.nitlanguage.org).
#
# Copyright 2013 <NAME> <<EMAIL>>
# Copyright 2014 <NAME> <<EMAIL>>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Low-level wrapper around the libevent library to manage events on file descriptors
#
# For mor information, refer to the libevent documentation at
# http://monkey.org/~provos/libevent/doxygen-2.0.1/
module libevent is pkgconfig("libevent")

in "C header" `{
	#include <sys/stat.h>
	#include <sys/types.h>
	#include <fcntl.h>
	#include <errno.h>
	#include <sys/socket.h>

	#include <event2/listener.h>
	#include <event2/bufferevent.h>
	#include <event2/buffer.h>
`}

in "C" `{
	// Callback forwarded to 'Connection.write_callback'
	static void c_write_cb(struct bufferevent *bev, Connection ctx) {
		Connection_write_callback(ctx);
	}

	// Callback forwarded to 'Connection.read_callback_native'
	static void c_read_cb(struct bufferevent *bev, Connection ctx)
	{
		// TODO move to Nit code
		struct evbuffer *input = bufferevent_get_input(bev);
		size_t len = evbuffer_get_length(input);
		char* cstr = malloc(len);
		evbuffer_remove(input, cstr, len);
		Connection_read_callback_native(ctx, cstr, len);
	}

	// Callback forwarded to 'Connection.event_callback'
	static void c_event_cb(struct bufferevent *bev, short events, Connection ctx)
	{
		Connection_event_callback(ctx, events);

		// TODO move to Nit code
		if (events & BEV_EVENT_ERROR)
			perror("Error from bufferevent");
		if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
			bufferevent_free(bev);
			Connection_decr_ref(ctx);
		}
	}

	// Callback fowarded to 'ConnectionFactory.spawn_connection'
	static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd,
		struct sockaddr *address, int socklen, ConnectionFactory ctx)
	{
		// TODO move to Nit code
		struct event_base *base = evconnlistener_get_base(listener);
		struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

		Connection nit_con = ConnectionFactory_spawn_connection(ctx, bev);
		Connection_incr_ref(nit_con);

		bufferevent_setcb(bev,
			(bufferevent_data_cb)c_read_cb,
			(bufferevent_data_cb)c_write_cb,
			(bufferevent_event_cb)c_event_cb, nit_con);
		bufferevent_enable(bev, EV_READ|EV_WRITE);
	}
`}

# Structure to hold information and state for a Libevent dispatch loop.
#
# The event_base lies at the center of Libevent; every application will
# have one.  It keeps track of all pending and active events, and
# notifies your application of the active ones.
extern class NativeEventBase `{ struct event_base * `}

	# Create a new event_base to use with the rest of Libevent
	new `{ return event_base_new(); `}

	# Has `self` been correctly initialized?
	fun is_valid: Bool do return not address_is_null

	# Event dispatching loop
	#
	# This loop will run the event base until either there are no more added
	# events, or until something calls `exit_loop`.
	fun dispatch `{ event_base_dispatch(self); `}

	# Exit the event loop
	#
	# TODO support timer
	fun exit_loop `{ event_base_loopexit(self, NULL); `}

	# Destroy this instance
	fun destroy `{ event_base_free(self); `}
end

# Spawned to manage a specific connection
#
# TODO, use polls
class Connection
	super Writer

	# Closing this connection has been requested, but may not yet be `closed`
	var close_requested = false

	# This connection is closed
	var closed = false

	# The native libevent linked to `self`
	var native_buffer_event: NativeBufferEvent

	# Close this connection if possible, otherwise mark it to be closed later
	redef fun close
	do
		if closed then return
		var success = native_buffer_event.destroy
		close_requested = true
		closed = success
	end

	# Callback method on a write event
	fun write_callback
	do
		if close_requested then close
	end

	private fun read_callback_native(cstr: NativeString, len: Int)
	do
		read_callback(cstr.to_s_with_length(len))
	end

	# Callback method when data is available to read
	fun read_callback(content: String)
	do
		if close_requested then close
	end

	# Callback method on events
	fun event_callback(events: Int) do end

	# Write a string to the connection
	redef fun write(str)
	do
		if close_requested then return
		native_buffer_event.write(str.to_cstring, str.bytelen)
	end

	redef fun write_byte(byte)
	do
		if close_requested then return
		native_buffer_event.write_byte(byte)
	end

	redef fun write_bytes(bytes)
	do
		if close_requested then return
		native_buffer_event.write(bytes.items, bytes.length)
	end

	# Write a file to the connection
	#
	# If `not path.file_exists`, the method returns.
{'fraction_non_alphanumeric': 0.08072359463139467, 'fraction_numerical': 0.003501264345458082, 'mean_word_length': 4.609929078014185, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4178578', 'n_tokens_mistral': 3464, 'n_tokens_neox': 3280, 'n_words': 1108}