I'm want to implement an API beetween Prolog and MongoDB and after some research the first hurdle would be connecting to MongoDB server. I know there's allready the API prolongo so I tried to understand it, but I don't. I'm a newbie in Prolog so my question is: Where is the actuall connect to the MongoDB server?
Edited: I've understood more of the code but I'm getting an error, that I can't interpret:
So here's the code of the mongo_connection.pl:
:- module(_, [
host/1,
port/1
]).
:- include(include/common).
%% host(?Host) is semidet.
%
% True if Host is the default hostname used by MongoDB.
host(localhost).
%% port(?Port) is semidet.
%
% True if Port is the default port used by MongoDB.
port(27017).
/** <module> Connection handling and response parsing.
*/
:- module(_, [
new_connection/1,
new_connection/3,
free_connection/1,
get_database/3,
send_to_server/2,
read_reply/4
]).
:- include(include/common).
%% new_connection(-Connection) is det.
%% new_connection(+Host, +Port, -Connection) is det.
%
% True if Connection represents an opaque handle to a new MongoDB
% server connection. Default values (see mongo_defaults) are used unless
% Host and Port are provided.
new_connection(Connection) :-
mongo_defaults:host(Host),
mongo_defaults:port(Port),
new_connection(Host, Port, Connection).
new_connection(Host, Port, Connection) :-
mongo_socket:new_socket(Host, Port, Socket),
Connection = connection(Socket).
connection_socket(Connection, Socket) :-
mongo_util:get_nth1_arg(Connection, 1, Socket).
%% free_connection(+Connection) is det.
%
% Frees any resources associated with the Connection handle,
% rendering it unusable.
free_connection(Connection) :-
connection_socket(Connection, Socket),
mongo_socket:free_socket(Socket).
%% get_database(+Connection, +DatabaseName, -Database) is det.
%
% True if Database is a handle to the database called DatabaseName
% on Connection. No communication is performed, so the actual database
% might or might not already exist.
get_database(Connection, DatabaseName, Database) :-
mongo_database:new_database(Connection, DatabaseName, Database).
%% send_to_server(+Connection, +Bytes) is det.
%
% True if Bytes are sent over Connection.
send_to_server(Connection, Bytes) :-
connection_socket(Connection, Socket),
mongo_socket:send_bytes(Socket, Bytes).
%% read_reply(+Connection, -Header, -Info, -Docs) is det.
%
% True if Header, Info and Docs together represent the next message
% received over Connection. Blocks until a message is completely read.
%
% Header is the structure header(MessageLength,RequestId,ResponseTo,OpCode)
% where:
% - MessageLength is the total number of bytes comprising the message
% - RequestId is the ID of this message (unused)
% - ResponseTo is the ID of the query that triggered this response (unused)
% - OpCode is the code signifying that this is a response (always 1)
%
% Info is the structure info(Flags,CursorId,StartingFrom,NumberReturned)
% where:
% - Flags is the bitmask of flags set for this response
% - CursorId is the cursor ID of this response
% - StartingFrom is the query offset of the first document in Docs
% - NumberReturned is the number of documents in Docs
read_reply(Connection, Header, Info, Docs) :-
connection_socket(Connection, Socket),
read_response_bytes(Socket, Bytes),
parse_response(Bytes, Header, Info, Docs).
read_response_bytes(Socket, [B0,B1,B2,B3|Bytes]) :-
read_message_length(Socket, [B0,B1,B2,B3], TotalLength),
read_rest_of_message(Socket, TotalLength, Bytes).
read_message_length(Socket, Bytes, Length) :-
mongo_socket:receive_n_bytes(Socket, 4, Bytes),
bson_bits:integer_bytes(Length, 4, little, Bytes).
read_rest_of_message(Socket, TotalLength, Bytes) :-
LengthRest is TotalLength - 4,
mongo_socket:receive_n_bytes(Socket, LengthRest, Bytes).
parse_response(Bytes, Header, Info, Docs) :-
% inspect_response_bytes(Bytes), % For debugging.
phrase(parse_response_meta(Header, Info), Bytes, RestBytes),
parse_response_docs(RestBytes, Docs).
parse_response_meta(Header, Info) -->
parse_response_header(Header),
parse_response_info(Info).
parse_response_header(Header) -->
{ Header = header(MessageLength,RequestId,ResponseTo,OpCode) },
mongo_bytes:int32(MessageLength),
mongo_bytes:int32(RequestId),
mongo_bytes:int32(ResponseTo),
mongo_bytes:int32(OpCode).
parse_response_info(Info) -->
{ Info = info(Flags,CursorId,StartingFrom,NumberReturned) },
mongo_bytes:int32(Flags),
mongo_bytes:int64(CursorId),
mongo_bytes:int32(StartingFrom),
mongo_bytes:int32(NumberReturned).
parse_response_docs(Bytes, Docs) :-
bson:docs_bytes(Docs, Bytes).
Here is the code of mongo_socket.pl:
:- module(_, [
new_socket/3,
free_socket/1,
send_bytes/2,
receive_n_bytes/3
]).
:- include(include/common).
%% new_socket(+Host, +Port, -Socket) is det.
%
% True if Socket is a new TCP socket connected to Host:Port.
%
% @throws mongo_error(Description, [SocketException])
new_socket(Host, Port, Socket) :-
setup_call_catcher_cleanup(
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),
exception(SocketException),
close_socket_and_throw(SocketId, SocketException)),
Socket = socket(ReadStream,WriteStream).
close_socket_and_throw(SocketId, Exception) :-
socket:tcp_close_socket(SocketId),
throw(mongo_error('could not connect to server', [Exception])).
socket_read(Socket, ReadStream) :-
mongo_util:get_nth1_arg(Socket, 1, ReadStream).
socket_write(Socket, WriteStream) :-
mongo_util:get_nth1_arg(Socket, 2, WriteStream).
%% free_socket(+Socket) is det.
%
% Frees any resources associated with Socket, rendering it unusable.
free_socket(Socket) :-
socket_read(Socket, ReadStream),
socket_write(Socket, WriteStream),
core:close(ReadStream, [force(true)]),
core:close(WriteStream, [force(true)]).
%% send_bytes(+Socket, +Bytes) is det.
%
% True if Bytes are sent (and flushed) over Socket.
send_bytes(Socket, Bytes) :-
socket_write(Socket, WriteStream),
send_bytes_and_flush(Bytes, WriteStream).
send_bytes_and_flush(Bytes, WriteStream) :-
core:format(WriteStream, '~s', [Bytes]),
core:flush_output(WriteStream).
%% receive_n_bytes(+Socket, +N, -Bytes) is det.
%
% True if Bytes is the next N bytes received over Socket.
receive_n_bytes(Socket, N, Bytes) :-
socket_read(Socket, ReadStream),
receive_n_bytes_aux(ReadStream, N, Bytes).
receive_n_bytes_aux(_ReadStream, 0, []) :- !.
receive_n_bytes_aux(ReadStream, N, [Byte|Bytes]) :-
core:get_byte(ReadStream, Byte),
N1 is N - 1,
receive_n_bytes_aux(ReadStream, N1, Bytes).
So with the lines
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),..
Prolog creates an INET-domain stream-socket. I'm using MS-Windows, and if the socket library is not yet initialised, this will also initialise the library.
But I'm getting this error:
So here are my questions:
- Am I trying to make the new connection with the wrong file?
- The Socket-library should be loaded automatically or do I have to put the prolongo-files into the the path "C:\Program Files\swipl\library"?
- How to interpret this error above?