diff --git a/include/el/msglink/msglink_protocol.md b/include/el/msglink/msglink_protocol.md
index c4f151c..f8bcea1 100644
--- a/include/el/msglink/msglink_protocol.md
+++ b/include/el/msglink/msglink_protocol.md
@@ -1,44 +1,44 @@
# Message Link
-Message link (msglink) is a custom networking protocol based on websockets that can be used to easily exchange data, events and commands between multiple systems over the network.
+Message link (msglink) is a custom networking protocol based on websockets that can be used to easily exchange data, events and commands between multiple systems over the network.
## Principles
-msglink tries to conform to these core principals:
+msglink tries to conform to the following core principles:
-- Simple API: It should be easy to start a msglink server and define client handling functionality without needing to decide between a thousand different transport protocols and other config
-- Clean and user-friendly API definition: event definition and use should be as simply as possible leveraging language specific features to abstract away the implementation details. There should be as little repeated boiler-plate as possible.
+- Simple API: It should be easy to start a msglink server and define client handling functionality without needing to decide between a variety of different transport protocols and other config
+- Clean and user-friendly API definition: event definition and use should be as simple as possible leveraging language specific features to abstract away the implementation details. There should be as little repeated boilerplates as possible.
- Platform independence: the protocol should be usable on any OS or system using multiple programming languages (protocol features should not depend on special language functions)
-- Simple state management: The user program shall not be required to manage any state related to the communication such as channel subscriptions or any of that stuff. A user should be able to say "I want this and this and this data" to the library and it must make sure these requests are fulfilled even after reconnects and similar incidents.
+- Simple state management: the user program shall not be required to manage any state related to the communication such as channel subscriptions or alike. A user should be able to say "I want this specific data" to the library and the program must make sure these requests are handled even after reconnects or similar networking events.
## Features
-msglink is similar to Socket.IO, except it provides additional functionality extending the simple event system.
+msglink is similar to Socket.IO, except it provides additional functionality extending the simple event system as follows:
- Strict types and data validation
-- Type-Defined events
+- Type-defined events
- Data subscriptions
- Remote Procedure calls (with return data)
## Strict types and data validation
-One of the most annoying and often repetitive coding tasks when it comes to network communication is serialization and deserialization (especially when communicating between different languages and platforms). At this point, JSON has become the defacto standard for most general purpose web APIs and many high-level communication protocols (at least where ever maximum performance and throughput is not the most important point). While JSON is a nice way to encode data both readable with relative ease by humans and computers, it is still a ton of work to encode and decode data in your application from/to the language-internal format.
+One of the most annoying (and often repetitive) coding tasks when it comes to network communication is serialization and deserialization (especially when communicating between different languages and platforms). At this point, JSON has become the defacto standard for most general purpose web APIs and many high-level communication protocols (at least where ever maximum performance and throughput is not the most important point). While JSON is a nice way to encode data, readable with relative ease by humans and computers likewise, it still remains a ton of work to encode and decode data in your application from or to the language-internal format.
-Most modern programming languages provide some sort of native or third party support for serializing and deserializing JSON, but the problem with JSON data received via the network is, that it is fully dynamic. You cannot be sure at the time of development what the JSON object will contain. So after parsing, it is required to manually go through the JSON object, checking that all it's fields match the type and restrictions required by your program. Then the data should ideally be extracted into some form of language-specific format like a struct in C/C++.
+Most modern programming languages provide some sort of native or third party support for serializing and deserializing JSON, but the problem with JSON data received via the network is, that it is fully dynamic. At the time of development you cannot be sure what the JSON object will contain at runtime. So after parsing, it is required to manually go through the JSON object, checking that all it's fields match the type and restrictions required by your program. Then the data should ideally be extracted into some form of language-specific format like a struct in C/C++.
-Luckily there are libraries that can help us simplify this task. The Python library PyDantic provides a way to elegantly define a JSON property's type, value restrictions and optional (de)serializer functions and enables simple parsing and automatic validation of incoming data. Since everything is represented by classes, static type checkers can see the datatype of properties and provide excellent editor support. In Swift, the Codable protocol is natively supported and provides similar functionality. In some languages like C++ this is not quite as simple to represent but we can still simplify the process.
+Luckily though, there are libraries that can help us simplify this task. The Python library PyDantic provides a way to elegantly define a JSON property's type, value restrictions and optional (de)serializer functions and enables simple parsing and automatic validation of incoming data. Since everything is represented by classes, static type checkers can see the datatype of properties and provide excellent editor support. In Swift, the Codable protocol is natively supported and provides similar functionality. In some languages like C++ this is not quite as simple to represent but we can still simplify the process.
-msgpack tries to implement and require these type definitions natively in it's implementation libraries, each in the style and with the features supported by the respective programming language. This way, every event has a clearly defined data structure passed along the event. Event listeners can access incoming data in the language-native format and rely on the fact that they receive what they expect. Event emitters on the other hand can pass data in the language-native format and will be forced to only emit valid data for a specific event.
+msglink tries to implement and require these type definitions natively in it's implementation libraries, each in the style and with the features supported by the respective programming language. This way, every event has a clearly defined data structure passed along the event. Event listeners can access incoming data in the language-native format and rely on the fact that they receive what they expect. Event emitters on the other hand can pass data in the language-native format and will be forced to only emit valid data for a specific event.
## Type-defined events
-Traditionally, events have been identified by a simple string, it's name. There is nothing inherently wrong with this approach, but it introduces additional places to make mistakes. One may want to listen to the same event in multiple places of a program but might make a typo when identifying the event name or forget to update one listener after changing the name.
+Traditionally, events have been identified by a simple string, it's name. There is nothing inherently wrong with this approach, but it introduces additional places to make mistakes. One may want to listen to the same event in multiple places of a program but might make a typo when identifying the event name or forget to update a listener after changing the name.
-Language features such as enums, constants or TS literal types will solve this issue. msglink aims to integrate this as a requirement in it's implementation. This goes hand-in-hand nicely with the previous point, strict types. Every event has to have a defined and validatable data type which also defines the name of the event it is associated with. After defining it once, this event type can be used everywhere in the program (details depend on language implementation) to refer to this specific event, there cannot be typos in the event name and it is impossible emit events with the wrong data structure.
+Language features such as enums, constants or TS literal types will solve this issue. msglink aims to integrate this as a requirement in it's implementation. This goes hand-in-hand nicely with the previous point, strict types. Every event has to have a defined and validatable data type which also defines the name of the event it is associated with. After defining it once, this event type can be used everywhere in the program (details depend on language implementation) to refer to the specific event. Typos in the event name can be avoided and it is impossible to emit events with the wrong data structure.
## Data subscriptions
@@ -47,16 +47,16 @@ Everything up to this point has just been library implementation specific improv
Data subscriptions basically allow a communication party to "subscribe" to a certain data source in THE OTHER PARTY's ENVIRONMENT. At first, this may sound similar to event listeners, however there is a key difference. In the usual event system, party A doesn't know what events party B listens to. Whenever a communication party has something to offer, it simply emits an event and the other party decides if it is interested in it.
-Data subscriptions on the other hand, allow one party (we will call it the client although it doesn't matter which one is the client and which one is the server) to tell the other (the server) that it needs some data value (for example a list of all online users). The server will then send the client the requested information and also automatically send an update whenever the data changes in some way on the server. This is especially useful if the server itself needs to get these value updates from some other system and needs to subscribe/listen to them on demand (or if there are too many events to just send all of them all the time).
+Data subscriptions on the other hand, allow one party (we will call it the client, although it doesn't matter which one is the client and which one is the server) to tell the other (the server) that it needs some data value (for example a list of all online users). The server will send the requested information to the client and automatically send an update whenever the data on the server changes in some way. This is especially useful if the server itself needs to get these value updates from some other system and needs to subscribe/listen to them on demand (or if there are too many events to just send all of them all the time).
-These data sources do not need to be part of a static API definition that is hard-coded and known by both parties beforehand. For example, a client might want to know the activity status of user "xyz" and get automatic updates on it. But maybe user "xyz" doesn't even exist. The client can still request the wanted data source from the server, and if the server can provide it it will do so. If the server cannot provide the data source, it will respond with a not-available error or send the data as soon as it is available, depending on what is required.
+These data sources do not need to be part of a static API definition that is hard-coded and known by both parties beforehand. For example, a client might want to know the activity status of user "xyz" and get automatic updates on it. But maybe user "xyz" doesn't even exist. The client can still request the data source from the server, and if the server can provide it, it will do so. If the server cannot provide the data source, it will respond with a not-available error or send the data as soon as it is available, depending on what is required.
The same functionality can be implemented with simple messages, however since this is used so frequently, it gets repetitive and error-prone quite quickly. By implementing this feature in a library, the repetitive parts can be abstracted and we can even use language/framework specific features to make such "remote" data sources even more convenient to use (e.g. React State or Svelt Stores).
## Remote Procedure calls
-Another common use-case for messaging protocols is a remote procedure calls. A remote procedure call consists of one communication party sending some data to the other one and causing some code to run there. Once the other party is finished, it will return the result to the calling party.
+Another common use-case for messaging protocols is a remote procedure call. A remote procedure call consists of one communication party sending some data to the other one and causing some code to run there. Once the other party is finished, it will return the result to the calling party.
A remote procedure call can be implemented by emitting an event and running some action in the even listener. At the end of the listener, another event has to be emitted containing the result returned to the client.
@@ -67,7 +67,7 @@ msglink avoids this by implementing the base functionality once and providing a
## Decision criteria
-Which of the three options provided by msglink (events, data subscriptions, RPCs) to use depends on a few criteria:
+It depends on a few criteria, which of the three options provided by msglink (events, data subscriptions, RPCs) shoud be used:
- **value or incident** focus: What's more important? The actual data value or the fact that it changed?
> If the focus is on the value of some datum, a data subscription should be used. It has different syntax to events allowing it to be easily used as a (possibly observable) remote-synced variable.
@@ -76,29 +76,29 @@ Which of the three options provided by msglink (events, data subscriptions, RPCs
>
> In short: The focus of events is to run some code when something happens while the focus of a data subscription is to have some data value that can be accessed at any time without worrying about updating it.
- **conditionality**: When and for how long is some data needed and when do events need to be transmitted?
- > Both event listeners and data subscriptions offer a way to "enable" and "disable" them during the lifetime of the program. It is strongly encouraged for library implementations to use of language features such as scope and object lifetime to determine when events and data subscription updates are needed in a granular way. This can save on network bandwidth.
+ > Both event listeners and data subscriptions offer a way to "enable" and "disable" them during the lifetime of the program. For Library implementations it is strongly encouraged to use language features such as scope and object lifetime to determine when events and data subscription updates are needed in a granular way. This can save on network bandwidth.
>
- > When listening to an event, a handler function (listener) is registered which is then called whenever an event is received from the other party. Registering a listener may yield an object or handle representing it. This object can then be used to manage the lifetime of the listener. For example in C++, if an event is only needed inside a class instance, the listener object should be a member of that class and be unregistered whenever the class instance is destroyed (goes out of scope).
+ > When listening to an event, a handler function (listener) is registered which is called whenever an event is received from the other party. Registering a listener may yield an object or handle representing it. This object can then be used to manage the lifetime of the listener. For example in C++, if an event is only needed inside a class instance, the listener object should be a member of that class and be unregistered whenever the class instance is destroyed (i.e. goes out of scope).
>
> When subscribing to some data using data subscriptions, a similar object/handle will be created. Again in C++, it might be used to directly access the data using the arrow operator and manage the lifetime of the data subscription like the event listener object.
-- **uniqueness**: Is a piece of data/event unique or are there multiple multiple different ones with the same structure and meaning?
- > Uniqueness means, that exactly one of something exists.
+- **uniqueness**: Is a piece of data/event unique or are there multiple different ones with the same structure and meaning?
+ > Uniqueness means, that exactly one (entity) of something exists.
>
> In the msglink protocol, events (not event instances) are unique entities. Let's say, there is an event called "device_connect". In the entire application, there is only one such event with a clearly defined data structure associated with it. However, when emitting the event, the data value may be different every time. For example this event might have a "device_id" parameter which uniquely identifies the device that has joined. No matter what the device ID is, every listener for "device_connect" will receive the event.
>
- > Sometimes you may only want a listener to be called when the device with a specific ID is connected. You cannot define a different event for each device ID, because it would be very tedious and you probably don't even known at compile time what device IDs exist. Instead this would require some sort of filter, comparing the actual data. This can be done inside the listener function, but that has a big disadvantage: Even though only events with a specific device ID are required, all "device_connect" events are still transmitted over the network. And then you probably need to do the same thing with the "device_disconnect" event.
+ > Sometimes you may only want a listener to be called when the device with a specific ID is connected. You cannot define a different event for each device ID, because it would be very tedious and you probably don't even known which device IDs exist at all at compile time. Instead this would require some sort of filter, comparing the actual data. This can be done inside the listener function, but has as well a big disadvantage: Even though only events with a specific device ID are required, all "device_connect" events are still transmitted over the network. And then you probably need to do the same thing with the "device_disconnect" event.
>
- > In such a situation, what you really want is a data subscription which can have subscription parameters. So you might define a data source called "device_connected" which may have a boolean property "is_connected" which can be true or false. Then you define the subscription parameter to have a property "device_id". When this data source is subscribed, a device ID has to be passed to that call. The providing party can then immediately respond saying that it either can or cannot provide the data for the given device ID. If it can, it will then only update the online value for that device ID and all others will not be transmitted over the network.
+ > In such a situation, what you really want is a data subscription which can have subscription parameters. So you might define a data source called "device_connected" which may have a boolean property "is_connected" which can be true or false. Then you define the subscription parameter to have a property "device_id". When this data source is subscribed, a device ID has to be passed to that call. The providing party can then immediately respond saying that it either can or cannot provide the data for the given device ID. If it can, it will then update the online value for only that device ID and all others will not be transmitted over the network.
- **confirmation**: Does some event require any form of confirmation/response/result from the other party?
> When the goal is for one communication party to cause some sort of action by the other party, an event can be used.
>
- > However often times the executing party needs send some result data or outcome of the action back to the emitter. In the past, it was necessary to define a separate request and response event and write code for every type of interaction to sync the two up, wait for the response and so on. This is very tedious and repetitive.
+ > However, sometimes the executing party needs to send some result data or outcome of the action back to the emitter. In the past, it was necessary to define a separate request and response event and write code for every type of interaction to sync the two up, wait for the response and so on. This is very tedious and repetitive.
>
> With msglink, for such a case a procedure can be defined instead of an event. A procedure is basically two events combined, with the only difference being that the listener now returns another object which is sent back to the emitter. This can be integrated nicely with the async programming capability of many programming languages.
>
> Another difference between procedures and events is the way that they are handled on the receiving side. Since events have no way of returning data or results to the emitter, there may be many listeners that are notified of the event and can perform actions when that happens. Although each of them may cause various actions, like emitting more events as a response, none of them are responsible for or capable of defining one singular "outcome" or "result" of the event. This is a broadcast theme.
>
- > With procedures, this is different. Since a procedure has to have one single definite result to be sent back to the caller (roughly equivalent to emitter for events) after it has been handled, there can only be one handler. A procedure may be called from many different places, but on the receiving side, there has to be exactly one handler (function). Since it is necessary for a complete transaction to always return a result, it is also not allowed for there to be no handler at all. So procedures always have exactly one handler.
+ > With procedures, this is different. Since a procedure has to have one single definite result to be sent back to the caller (roughly equivalent to emitter for events) after it has been handled, there can be only one handler. A procedure may be called from many different places, but on the receiving side, there has to be exactly one handler (function). Since it is necessary for a complete transaction to always return a result, it is also not allowed for there to be no handler at all. So procedures always have exactly one handler.
# Protocol details
@@ -107,7 +107,7 @@ In the following section, the details of the communication protocol will be desc
As an example we are using a system managing multiple hardware devices connected to some computer. A webapp (client) displays information about connected devices and allows managing them by communicating with a server running on that computer.
-The client needs:
+The client needs the following:
- to be informed when an error occurs
**Indicent without response -> event: "error_occurred"**
@@ -118,7 +118,7 @@ The client needs:
- the ability for the user to disable a device, for example because it needs to much power
**Command with response -> RPC: "disable_device"**
-> In msglink there is (almost) no difference between the client and the server except for how the socket connection is established (and transaction IDs which are covered below). Therefore, any example described here could just as well work in the other direction.
+> In msglink there is (almost) no difference between the client and the server except for (a) how the socket connection is established and (b) transaction IDs (which are covered below). Therefore, any example described here could just as well work in the other direction.
## The basics
@@ -161,11 +161,11 @@ The **```type```** property defines the purpose of the message. There are the fo
The **```tid```** property is the transaction ID. The transaction ID is a signed integer number which (within a single session) uniquely identifies the transaction the message belongs to.
> A transaction is a (from the perspective of the protocol implementation) complete interaction between the two communication parties. It could be an event, a data subscription or an RPC.
-This is a scheme used by many networking protocols and is required for the communication parties to know what messages belong together when a single transaction requires multiple back-and-forth messages like during an RPC. This is one of those tedious repetitive things that would otherwise need to be reimplemented for every command-response event pair if it was implemented manually using only events.
+This is a scheme used by many networking protocols and is required for the communication parties to know what messages belong together when a single transaction requires multiple back-and-forth messages like during an RPC. This is one of those tedious repetitive things that otherwise would need to be reimplemented for every command-response event pair if it was implemented manually using only events.
-Every time a communication party starts a new interaction, it first generates a new transaction ID by using an internal ID counter. To prevent both parties from generating the same transaction ID at the same time, the **server always starts at transaction ID 1 and increments** it for each new transaction it starts (1, 2, 3, 4, ...) while the **client always starts a transaction ID -1 and decrements** from there (-1, -2, -3, -4, ...). Eventually, the two will meet in the middle when the integer overflows, which will take a very long time assuming 64 bit (or even 32 bit) integers.
+Every time a communication party starts a new interaction, it first generates a new transaction ID by using an internal ID counter. To prevent both parties from generating the same transaction ID at the same time, the **server always starts at transaction ID 1 and increments it** for each new transaction it starts (1, 2, 3, 4, ...) while the **client always starts a transaction ID -1 and decrements it** from there (-1, -2, -3, -4, ...). Eventually, the two will meet "in the middle" when the integer overflows, which will take a very long time (assuming 64 bit or even 32 bit integers).
-The names of properties are intentionally kept as short as possible while still being readable pretty well by humans to reduce message size.
+The names of properties are - intentionally - kept as short as possible while still being readable pretty well by humans to reduce message size.
Messages can have other properties specific to the message type.
@@ -219,7 +219,7 @@ The message also contains lists of all the functionality the party can provide t
- **remote procedure calls**: one party's called procedures list must be a subset of the other's callable procedure list. Fails with code 3005. Fail reasons:
- If one party may call a procedure the other doesn't know about and cannot handle
-Obviously these requirements are only checked approximately. The client doesn't know at that point whether the server ever will emit the "error_occurred" event or even if there will ever be a listener for it. The only thing it knows is that both the server and itself know that this event exists and know how to deal with it should that become necessary later.
+Obviously these requirements are only checked approximately. The client doesn't know at that point whether the server ever will emit the "error_occurred" event or even if there will ever be a listener for it. The only thing it knows is that both the server and itself know that this event exists and know how to deal with it (should that become necessary later).
If no problems were found, each party sends an authentication acknowledgement message as a response to the other with the respective transaction ID (not a new one) to complete the authentication transaction:
@@ -230,7 +230,7 @@ If no problems were found, each party sends an authentication acknowledgement me
}
```
-Only after both parties' authentication transactions have been successfully completed, is either party allowed to send further messages. This is defined by one party as both:
+Only after both parties' authentication transactions have been successfully completed, either party is allowed to send further messages. This is defined by one party as both:
- having sent the auth_ack message in response to the other's auth message
- having received the auth_ack message in response to it's own auth message
diff --git a/include/el/msglink/networking_architecture.md b/include/el/msglink/networking_architecture.md
index fa179bd..08eb562 100644
--- a/include/el/msglink/networking_architecture.md
+++ b/include/el/msglink/networking_architecture.md
@@ -1,6 +1,6 @@
# msglink networking architecture
-in addition to defining a protocol and convenient abstraction libraries for using it, msglink libraries also define a number of different networking topologies and convenient support for them in library implementations.
+In addition to defining a protocol and convenient abstraction libraries for using it, msglink libraries also define a number of different networking topologies and convenient support for them in library implementations.
This page describes the common internal architecture "stack" of msglink implementation libraries as well as different ways multiple communication parties can interact with each other over the network.
@@ -9,7 +9,7 @@ This page describes the common internal architecture "stack" of msglink implemen
An application using the msglink protocol is divided into three blocks:
-- **Network Interface**: This block is responsible for opening, maintaining and closing a network connection to the other communication party as well as sending and receiving protocol data units (here messages). It also manages and updates the other blocks higher up in the stack depending on the network connection state.
+- **Network Interface**: This block is responsible for opening, maintaining and closing a network connection to the other communication party as well as sending and receiving protocol data units (here: messages). It also manages and updates the other blocks higher up in the stack depending on the network connection state.
- **Link Interface**: This is a small block which is used by the link to communicate to the network interface for sending data and controlling the connection based on the protocol.
- **Link**: This block is the responsible for managing the protocol. It receives/sends and decodes/encodes messages from/to the network interface and performs actions according to the msglink protocol. This part is responsible for performing authentication with the other party as soon as a connection is established, checking protocol compatibility, managing event- and data-subscriptions, keeping track of RPC transactions and more.
@@ -20,6 +20,7 @@ The user of the msglink library must customize the **link** by defining their ap
In the C++ library, this is accomplished by first defining a class/struct for each event, data subscription and remote procedure:
```cpp
+
// can be incoming, outgoing or both (bidirectional)
struct didi_event : public el::msglink::bidirectional_event
{
@@ -33,10 +34,11 @@ struct didi_event : public el::msglink::bidirectional_event
)
};
-// ... more events and other stuff
+// ... more events and other stuff here
+
```
-Then, a custom link class has to be created which defines all of the events, data subscriptions and procedures that are part of the application specific "protocol". There, you might also configure some static listener functions called when an e.g. an event is received:
+Then, a custom link class has to be created which defines all of the events, data subscriptions and procedures that are part of the application specific "protocol". There, you might also configure some static listener functions called when (for example) an event is received:
```cpp
@@ -77,7 +79,7 @@ public:
Once the link has been defined, it can the be used when connecting with another communication party. The actual network connection part can vary greatly depending on the use case and is explained in more detail in [Networking topologies](#networking-topologies).
-For the communication to work, both parties need to have a compatible link. The link is compatible if all of the below are true:
+For the communication to work, both parties need to have a compatible link. The link is compatible if all of the following conditions are true:
- msglink versions are compatible
- user defined link version (```EL_MSGLINK_LINK_VERSION(...)```) matches
@@ -86,59 +88,59 @@ For the communication to work, both parties need to have a compatible link. The
## Networking topologies
-In the context of this document, the them "networking topology" refers to the relation between client and server parties in a msglink communication session.
+In the context of this document, the term "networking topology" refers to the relation between client and server parties in a msglink communication session.
-At it's core, msglink is a point-to-point communication protocol. msglink never uses broadcasts or multicasts on a network level. There are always two parties A and B communication with each other using the msglink protocol.
+At it's core, msglink is a point-to-point communication protocol. msglink never uses broadcasts or multicasts on a network level. There are always exactly two parties A and B communication with each other using the msglink protocol.
-In the msglink protocol, there is no logical difference between a client and a server. Both communication parties are equal and have equal capabilities (in the bounds defined by the user application).
+In the msglink protocol, there is no logical difference between a client and a server. Both communication parties are equal and have equal capabilities (within the bounds defined by the user application).
-However, at some point, a network connection (Websocket, which builds ontop of TCP socket) needs to be established as a communication channel. For that to work, one of the two parties needs to act as a server, listening for a new connection by the other party. It is the job of the **Network Interface** architecture block to manage this connection phase. This network interface block is typically represented by a class. There are multiple network interface blocks that the user of the library can select from to assign a communication party the appropriate role in the connection establishing phase.
+However, at some point, a network connection (websocket, which builds ontop of TCP socket) needs to be established as a communication channel. For that to work, one of the two parties needs to act as a server, listening for a new connection by the other party. It is the job of the **Network Interface** architecture block to manage this connection phase. This network interface block is typically represented by a class. There are multiple network interface blocks the user of the library can select from to assign a communication party the appropriate role in the connection-establishing phase.
### Networking role selection
Depending on the application, the user may arbitrarily define either party to be the server or the client by using the corresponding network interface class ```el::msglink::server``` or ```el::msglink::client```.
-In many cases, like a WebApp, the role selection is obvious. In this example, it only makes sense for a program running on the webserver with a public facing IP address to be the msglink server and the browser to be the client.
-In most applications, one party is clearly the "boss" of operations and it therefor makes sense for that one to be the server.
+In many cases, such as a WebApp, the role selection is obvious. In this example, it only makes sense for a program running on the webserver with a public facing IP address to be the msglink server and the browser to be the client.
+In most applications, one party is clearly the "boss" of operations and it therefore makes sense for that one to be the server.
-In a scenario two equivalent devices such as two robots on the same network communicating directly with each other, it might not matter which one is the server. When selecting the before mentioned interface classes, there is only a minimal difference in the library API.
+In a different scenario with two equivalent devices (such as two robots on the same network communicating directly with each other), it might not matter which one is the server. When selecting from the before mentioned interface classes, there is only a minimal difference in the library API.
### Connection loss and reconnects
-In msglink, the protocol an communication state is managed by the **Link** class, while the network connection state is managed by the **Network Interface** class such as ```el::msglink::server``` or ```el::msglink::client```. When a connection is first established, the network interface instance notifies the link instance and it can perform authentication. Once that is done, the two parties might exchange event subscriptions and start communicating.
+In msglink, the protocol and communication state is managed by the **Link** class, while the network connection state is managed by the **Network Interface** class such as ```el::msglink::server``` or ```el::msglink::client```. When a connection is first established, the network interface instance notifies the link instance and it can perform authentication. Once that is done, the two parties might exchange event subscriptions and start communicating.
-But what happens when the connection is lost? msglink intentionally doesn't define any convoluted method for attempting to restore a lost connection and resume communication where it left off. When the connection is closed, it's closed for good and must be restarted from scratch.
+But what happens when the connection is lost? By intention, msglink does not define any convoluted method for attempting to restore a lost connection and resume communication where it was left off. When the connection is closed, it's closed for good and must be restarted from scratch.
Since the communication is not resumed where it left off, we might as well delete the link instance entirely. As soon as the client detects the connection has closed, it can attempt to reconnect to the server the same way as before. A new link instance would be created and the authentication procedure repeated the same way. But what happens to the event subscriptions and event listeners present before the connection loss? They would just be forgotten entirely and the user application would need to make sure what was required and what listener functions were registered in order to re-subscribe to all the events. This would be very tedious for the user to implement.
-For this reason, in a simple application were there is only one client and server which need to communicate, the **Link** block is completely decoupled from the **Network Interface** block. For the entire lifetime of an application, there will be a single instance of the user-defined link class that is never deleted. The network interface block will simply receive a reference to this instance to control it. Internally in the link class, the user protocol state (subscriptions, ...) is also decoupled from the network and msglink protocol state (authentication, transactions, ...).
+For this reason in a simple application, where there is only one client and one server which need to communicate, the **Link** block is completely decoupled from the **Network Interface** block. For the entire lifetime of an application, there will be a single instance of the user-defined link class that is never deleted. The network interface block will simply receive a reference to this instance to control it. Internally in the link class, the user protocol state (subscriptions, ...) is also decoupled from the network and msglink protocol state (authentication, transactions, ...).
-Initially, the link instance is in a disconnected state, were the network interface block has not jet created a connection to the other party. During this time, other parts of the application can already access the link instance and register event listeners or emit events. They will not notice the connection isn't established jet and the link will keep track internally of which events are subscribed and may queue up emitted events (depending on configuration)
-As soon as a connection is established and the authentication process is complete, the link will send all the event subscriptions for the currently required events according to it's internal records as well as possibly pushing queued event emissions.
+Initially, the link instance is in a disconnected state, were the network interface block has not yet created a connection to the other party. During this time, other parts of the application can already access the link instance and register event listeners or emit events. They will not notice the connection isn't established yet, and the link will keep track internally of which events are subscribed and may queue up emitted events (depending on configuration).
+As soon as a connection is established and the authentication process is complete, the link will send all the event subscriptions for the currently required events according to it's internal records, as well as possibly pushing queued event emissions.
Any event subscriptions and other state changes made while the connection is established are immediately sent to the other party as well as recorded internally, so the link instance knows at all times what event subscriptions, data subscriptions, etc. it currently needs.
-When the connection is lost, both parties' network connection blocks will reset the link instance' msglink protocol and networking state to a time before authentication. This does not affect user protocol state such as event subscriptions. Form then on, the link will behave like it did before the connection was established. Any access by the rest of the application will be recorded so the current state and missed events can be sent to the other party as soon it reconnects, ensuring the state of the communication subsystem will always be clean and the communication channel behaves as the user application expects.
+When the connection is lost, both parties' network connection blocks will reset the link instance' msglink protocol and networking state to a time before authentication. This does not affect user protocol state such as event subscriptions. From then on, the link will behave like it did before the connection was established. Any access by the rest of the application will be recorded so the current state and missed events can be sent to the other party as soon it reconnects, ensuring the state of the communication subsystem will always be clean and the communication channel behaves as the user application expects.
### many-to-one relationship
-In many cases, such as a server for a WebApp, it might be required for a server application to handle connection to multiple independent clients at the same time, dynamically. This is called a many-to-ony relationship. To support this functionality, you can use a special network interface class instead of teh basic server: ```el::msglink::multi_connection_server```. This class dynamically creates link instances for each client that connects to the server as well as calling a "client connected" handler to perform some initialization for the new client.
+In many cases, such as a server for a WebApp, it might be required for a server application to dynamically handle connections to multiple independent clients at the same time. This is called a many-to-ony relationship. To support this functionality, you can use a special network interface class instead of the basic server: ```el::msglink::multi_connection_server```. This class dynamically creates link instances for each client that connects to the server as well as calling a "client connected" handler to perform the initialization for a new client.
-This poses a problem when it comes to client state management however. As explained before, the user protocol state is kept within the link instance. In the simple server application only only exactly one connection, there was one global link instance. A server handling many connections needs to initialize links dynamically as soon as a client connects.
+However, this poses a problem when it comes to client state management. As explained before, the user protocol state is kept within the link instance. In a simple server application with exactly one connection, there is one global link instance. A server handling many connections needs to initialize links dynamically as soon as a client connects.
-So when a connection is lost, what happens to the link instance? Surely it cannot be kept around forever. Since there are many clients, it is tricky to tell wether a client is trying to reconnect or it's simply a new client connecting, which makes it hard to match a new connection to an existing link. That would require some sort of session identifier, which is currently not supported by msglink (more on that later).
+When a connection is lost, what happens to the link instance? Surely it cannot be kept around forever. Since there are many clients, it is tricky to tell wether a client is trying to reconnect or it's simply a new client connecting, which makes it hard to match a new connection to an existing link. That would require some sort of session identifier, which is currently not supported by msglink (more on that below).
Luckily we can work around this issue in many cases by changing the design philosophy of the application or just viewing it differently.
-When there is a server responsible for *serving* a large number of clients, it is unlikely for the server to *desperately want to get some specific piece of information globally* from *a* specific client. Instead, in most cases the clients probably want's to get notified about events from the server, so the server might not even have any event subscriptions for the client. If the client want's the server to do something, an RPC is probably better suited. And for the cases were client events are listened to by the server, every client probably has it's own event listeners associated to it, which are registered as soon as the link is instantiated when the client connects (probably methods of the link itself). In most cases the server isn't going to say *I now temporarily need to be notified about this event from the client* during runtime. And once a client disconnects, the server probably doesn't care about a specific event from that client, as it is the client which *wants* to send the information to the server.
+When there is a server responsible for *serving* a large number of clients, it is unlikely for the server to *desperately get some specific piece of information globally* from a specific client. Instead, in most cases the clients probably want to get notified about events from the server, so the server might not even have any event subscriptions for the client. If the client want's the server to do something, an RPC probably suits better. And for the cases were client events are listened to by the server, every client probably has it's own event listeners associated to it, which are registered as soon as the link is instantiated when the client connects (probably methods of the link itself). In most cases the server isn't going to say *I now temporarily need to be notified about this event from the client* during runtime. And once a client disconnects, the server probably doesn't care about a specific event from that client, as it is the client which *wants* to send the information to the server.
### Link lifetime
-For all these reasons, the ```el::msglink::multi_connection_server``` doesn't reconnect clients to existing links. The lifetime of a link is from when the connection is first established to when the connection is closed for whatever reason.
+For all these reasons, the ```el::msglink::multi_connection_server``` doesn't reconnect clients to existing links. The lifetime of a link ranges from when the connection is first established to when the connection is closed for any reason.
-The simple ```el::msglink::server``` class and also the ```el::msglink::client``` class keep the link around for the lifetime of the application, meaning the link is created when the application launches and deleted when it exits. Since these only have one global link instance, they reconnect it to the connection after the connection is closed.
+The simple ```el::msglink::server``` class and also the ```el::msglink::client``` class keep the link around for the lifetime of the application, meaning the link is created when the application launches and deleted when it exits. Since these classes only have one global link instance, they reconnect it to the connection after the connection is closed.
> ### Note
> The ```el::msglink::multi_connection_server``` is made for multiple ```el::msglink::client```s to connect to it. Even though the server-side link is not persistent, the client still only has one global link instance which behaves as described in the single-connection example. So when a client looses connection to a multi connection server, it still keeps and re-activates it's subscriptions just as expected.
-In the future it might be possible to add support for some sort of session identifier to the msglink authentication procedure that the client (which has a persistent link) remembers after the initial connect. When the multi connection server detects a connection loss without the connection being properly closed beforehand, it can keep it's link instance alive and reconnect it to the next new connection that authenticates with the same session identifier.
+In the future it might be possible to add support for some sort of session identifier to the msglink authentication procedure that the client (which has a persistent link) remembers after the initial connect. When the multi connection server detects a connection loss without the connection being properly closed beforehand, it can keep it's link instance alive and reconnects it to the next new connection that authenticates with the same session identifier.