-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
143 changed files
with
15,761 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Empty file.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
= Chat: Design Overview = | ||
|
||
<<wip|Warning this tutorial is not maintained and is not up to date.>> | ||
|
||
//Chat// is a chatting module and application, currently for conversations | ||
between two users each. (Extension for multi-user channels is left as an | ||
exercise to the user.) | ||
|
||
You can find the code [[https://github.com/ocsigen/tutorial/tree/master/src-examples|here]]. | ||
|
||
<<|* [[site:chat|try it]]! And | ||
* [[site:darcsweb/?r=tutorial;a=tree;f=/src-examples/chat|browse it]], | ||
* ##darcs get http://ocsigen.org/darcs/tutorial; cd tutorial/src-examples/chat## it, or | ||
* [[site:download/chat.tar.gz|download]] the source code. | ||
>> | ||
|
||
== Description == | ||
|
||
When the user is logged in, he sees a list of available users. He can choose | ||
one of them to start a conversation with him. The conversation then becomes | ||
visible to both users as a message prompt and a growing list of messages. The | ||
participating users can enter messages and they are made visible to the other | ||
participants. If a user becomes unavailable for //Chat//, he is removed from the | ||
list of available users, and all conversations he was participating are removed | ||
from the opponent's UI. | ||
|
||
== Central Data Types == | ||
|
||
The following data are crucial to the functionality of //Chat//. | ||
|
||
=== Conversation === | ||
A conversation (##type Shared.Conversation.t##) is shared between all its | ||
client participants. It comprises of two values: Firstly, it contains a bus for | ||
transferring conversation messages (c.f. ##type Shared.Conversation.message##) | ||
between the participants. Those are displayed as they come on every client. | ||
Secondly, it contains the set of participating users. This is used when the | ||
conversation is teared down: An event for removing the UI element for the | ||
conversation is sent to every participant. | ||
|
||
=== Client Process === | ||
When a user enters a web page which contains //Chat//, it is rendered in HTML and | ||
a new client process is created in doing so. Every client process holds a | ||
channel, where the server can send messages to //add or to remove conversations// | ||
(c.f. ##type Shared.event##). | ||
|
||
=== User Info === | ||
On the server side, the channel for those events is stored for each user along | ||
with a list of conversations he participates in. This is done with a | ||
Eliom-reference of scope ##session_group##, such that it is shared among all | ||
sessions of a user (and likewise all client processes). | ||
|
||
But, when one user requests to start (or end) a conversation with any another | ||
user, it is also necessary to access the event channel of any user. | ||
As it is only stored in an Eliom-reference specific to the user, it is | ||
impossible to access. In favour of this, the user info is moreover | ||
stored in a weak hash table (c.f. module ##Weak_info##) which associates the | ||
user info to each user in a globally accessible way. This association is weak | ||
in its value, the user info, such that it is garbage-collected as soon as the | ||
Eliom-reference storing it is cleared, i.e. when the last session of the | ||
respective user is closed. | ||
|
||
|
||
=== Available Users === | ||
The client's UI contains a list of users which are currently available for | ||
chatting. This is achieved as follows. | ||
|
||
If it is the user's first client process he is added to the set of available | ||
users, which is available in an react signal ##Chat.users_signal## on a set of | ||
user (i.e. ##User_set.t React.S.t##). | ||
As long as a user is available with at least one client he is kept in the value | ||
of the signal. This signal is send to the client when initializing //Chat//. | ||
Changes in its value are then directly reflected in the list of available users | ||
in the client's UI (c.f. ##Client.change_users##). | ||
|
||
To observe when a user is not available through a given client process anymore, | ||
//Chat// awaits for every client process that it is inactive for a given | ||
time. ##Eliom_comet.Channels.wait_timeout## is used for for detecting a client | ||
process to be abandoned. | ||
|
||
When it is observed that a user isn't avaible through any client process | ||
anymore, he is removed from the ##Chat.users_signal##, and all conversation he | ||
is participating are teared down (c.f. ##Chat.remove_client_process##). | ||
|
||
=== Starting a conversation === | ||
When the user selects one of the available users for a conversation, one of two | ||
things may happen (c.f. ##Client.create_or_focus_conversation##): | ||
|
||
Firstly, if there is already a conversation between exactly those two users, | ||
the message prompt is focused. | ||
Secondly, if there is no conversation between those users yet, a new one is created | ||
by calling the server's ##Chat.create_dialog_service## (dialog is a conversatio | ||
of two) with the selected user as argument. | ||
|
||
This service establishes the conversation between the users: It creates the | ||
conversation on the server side (i.e. the set of participants and the bus for | ||
messages) and sends an event to append the conversation to each participant. | ||
Each client is streaming such events (c.f. ##Client.dispatch_event##) and | ||
creates the respective UI-element for the conversation with event handlers for | ||
sending and receiving messages in the conversation. | ||
|
||
=== Sending a message in a conversationg === | ||
Sending messages within an conversation is achieved without any server-side | ||
code; the messages are sent "directly" to all all participants of the | ||
conversation //through its Eliom-bus//. Two things make this work. | ||
|
||
Firstly, an event listener on the message prompt of the conversation | ||
(c.f. ##Client.handle_enter_pressed##) awaits that the enter-key is hit in | ||
the message prompt of a conversation. It then creates a message and sends it | ||
to the conversation's event bus. | ||
|
||
Secondly, every participant of a conversation is streaming the messages which | ||
are sent over the conversation bus. | ||
A stream iterator on that bus then displays those messages as they arrive | ||
(c.f. ##Client.dispatch_message##). | ||
|
||
Have fun. [[site:chat|Be communicative!]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
=Custom configuration options= | ||
<<concepts |Custom configuration options>> | ||
|
||
It is not convenient to have to edit the code to change some | ||
configurations, like the location where are saved the favorite | ||
images in the Graffiti tutorial | ||
(see: [[wiki:pictures|Saving favorite pictures]]). | ||
Fortunately Ocsigen provides a mechanism to extend its | ||
configuration file. | ||
|
||
==Basic interface== | ||
|
||
<<code language="ocaml"| | ||
let static_dir = | ||
match Eliom_config.get_config () with | ||
| [Simplexmlparser.Element | ||
("staticdir", [], [Simplexmlparser.PCData dir])] -> | ||
dir | ||
| [] -> | ||
raise (Ocsigen_extensions.Error_in_config_file | ||
("staticdir must be configured")) | ||
| _ -> | ||
raise (Ocsigen_extensions.Error_in_config_file | ||
("Unexpected content inside config")) | ||
>> | ||
|
||
This will add a mandatory child to the eliom tag in the | ||
configuration file: | ||
{{{ | ||
<eliom module="path/to/your/module.cma"> | ||
<staticdir>/tmp/static</staticdir> | ||
</eliom> | ||
}}} | ||
|
||
|
||
==New interface== | ||
|
||
From Eliom 4.0 it is much easier to define configuration file extension. | ||
Have a look at module <<a_api project="eliom" subproject="server"|module Eliom_config>>. | ||
For instance, here is how you can add an element "<ldap>" | ||
in the configuration file to store a list of LDAP servers your application | ||
interacts with. | ||
|
||
|
||
<<code language="ocaml"| | ||
|
||
(** An LDAP server is characterized by an host and a port. *) | ||
type ldap_configuration = { | ||
mutable host : string; | ||
mutable port : int; | ||
} | ||
|
||
|
||
(** We store a list of LDAP servers to interact with. *) | ||
let ldap_servers = ref [] | ||
|
||
(** The user-defined extension of the configuration file. *) | ||
let ldap_configuration = Ocsigen_extensions.Configuration.( | ||
(** Default configuration *) | ||
let config () = { | ||
host = ""; | ||
port = 339; | ||
} | ||
in | ||
let init () = | ||
ldap_servers := config () :: !ldap_servers | ||
in | ||
let current () = | ||
List.hd !ldap_servers | ||
in | ||
|
||
(** Parsing functions. *) | ||
let req_attr name = attribute ~name ~obligatory:true | ||
and opt_attr name = attribute ~name ~obligatory:false | ||
in | ||
let name = "LDAP" | ||
and obligatory = false | ||
and attributes = [ | ||
req_attr "host" (fun h -> (current ()).host <- h); | ||
opt_attr "port" (fun p -> (current ()).port <- int_of_string p); | ||
); | ||
] | ||
in | ||
element ~init ~name ~obligatory ~attributes () | ||
) | ||
|
||
let _ = Eliom_config.parse_config [ldap_configuration] | ||
|
||
>> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[Dolphin] | ||
PreviewsShown=true | ||
Timestamp=2016,12,12,17,5,19 | ||
Version=3 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This code isn't maintened anymore and might not work. Please go to https://github.com/ocsigen/graffiti/simple for the latest working versions. |
Oops, something went wrong.