The server part of the system is written in \gls{iTasks}. Functions for
managing devices, \glspl{Task} and \glspl{SDS} have been created to support the
functionality. An interactive web application has been created that provides an
interactive management console for the \gls{mTask} system. This interface
provides functionality to list \glspl{SDS}, add and remove \glspl{Task},
administrate devices and view the state of the system.

\subsection{Device Storage}
Everything that a device encompasses is stored in the \CI{MTaskDevice} record
type. This includes management for the \glspl{SDS} and \glspl{Task} stored on
the device. The \CI{MTaskDevice} definition is shown in
Listing~\ref{lst:mtaskdevice} accompanied with the necessary classes and sub
types.

\begin{lstlisting}[caption={Device type},label={lst:mtaskdevice}]
:: Channels :== ([MTaskMSGRecv], [MTaskMSGSend], Bool)
:: BCState = ... // Compiler state, explained in later sections
:: MTaskResource
	= TCPDevice TCPSettings
	| SerialDevice TTYSettings
	| ...
:: MTaskDevice =
		{ deviceTask     :: Maybe TaskId
		, deviceError    :: Maybe String
		, deviceChannels :: String
		, deviceName     :: String
		, deviceState    :: BCState
		, deviceTasks    :: [MTaskTask]
		, deviceResource :: MTaskResource
		, deviceSpec     :: Maybe MTaskDeviceSpec
		, deviceShares   :: [MTaskShare]
	}

channels :: MTaskDevice -> Shared Channels

class MTaskDuplex a where
	synFun :: a (Shared Channels) -> Task ()
\end{lstlisting}

The \CI{deviceResource} component of the record must implement the
\CI{MTaskDuplex} interface that provides a function that launches a \gls{Task}
used for synchronizing the channels. The \CI{deviceTask} stores the
\gls{Task}-id for this \gls{Task} when active so that it can be checked upon.
This top-level task has the duty to report exceptions and errors as they are
thrown by setting the \CI{deviceError} field. All communication goes via these
channels. To send a message to the device, the system just puts it
in the channels. Messages sent from the client to the server are also placed
in there. In the case of the \gls{TCP} device type, the \gls{Task} is just a
simple wrapper around the existing \CI{tcpconnect} function in \gls{iTasks}. In
case of a device connected by a serial connection, it uses the newly developed
serial port library of \gls{Clean}\footnote{\url{%
https://gitlab.science.ru.nl/mlubbers/CleanSerial}}.

Besides all the communication information, the record also keeps track of the
\glspl{Task} currently on the device, the compiler state (see
Section~\ref{sec:compiler}) and the according \glspl{SDS}. Finally, it stores
the specification of the device that is received when connecting. All of this
is given in Listing~\ref{lst:mtaskdevice}. The definitions of the message
format are explained in the following section.

\subsection{Shares}
The system keeps track of the \glspl{SDS} stored on
the client in a big \gls{SDS} containing a list of devices. Client-\glspl{SDS}
can be stored on one device at the same time. This means that if an \gls{SDS}
updates, everyone watching it will be notified. This would result in a lot
of notifications that are not meant for the watcher. Moreover, when a client
updates the \gls{SDS} this is processed by the connection handler and results
in an update of the real \gls{SDS}. Finally, the \gls{SDS} of a client must be
synchronized with the actual device. Thus, when an \gls{iTasks}-\gls{Task}
writes the client-\gls{SDS}, it must be propagated to the real device. There
are several ways of tackling this problem each with their own level of
granularity.

First an actual \gls{iTasks}-\gls{SDS} for every \gls{SDS} used in a client can
be instantiated with one \gls{iTasks}-\gls{Task} listening to the \gls{SDS} and
synchronizing it with the device when an update occurred. This approach is very
expensive as it requires a lot of listening \glspl{Task}.

Improved on this, a single \gls{iTasks}-\gls{SDS} can be created for every
devices that stores the respective \glspl{SDS}. Using the \CI{mapReadWrite}
functions, a single \gls{SDS} per device can be created as a lens that allows
mapping on a single client-\gls{SDS}. However, this approach still requires
\glspl{Task} listening to the \gls{SDS} and when an \gls{SDS} is written,
everyone is notified, even if the \gls{Task} only uses the value of a single
different \gls{SDS}.

Finally, the current approach --- a single \gls{SDS} for the entire system
--- was explored. To create \glspl{SDS} per device or per client-\glspl{SDS} a
\CI{mapReadWrite} can be used but it suffers from the same problem as mentioned
before. Moreover, a \gls{Task} still has to watch the \gls{SDS} and communicate
the client-\gls{SDS} updates to the actual device. Both of these problems can
be solved by using a tailor made \gls{SDS} that heavily depends on parametric
lenses.

\subsection{Parametric Lenses}
The type for the parametric lens of the big \gls{SDS} is \CI{Maybe
(MTaskDevice, Int)}. The \gls{SDS} is responsible for storing the entire list
of devices, from now on global.  Moreover, the \gls{SDS} can focus on a single
device, from now on local. A local \gls{SDS} can also specifically focus on a
single \gls{SDS} on a single device, from now on called local-share. The
implementation of the real \gls{SDS} is given in Listing~\ref{lst:actualdev}.
The \gls{SDS} is a lens on an actual \gls{SDS} that writes to a file or memory.
Reading the \gls{SDS} is nothing more than reading the real \gls{SDS}. Writing
the \gls{SDS} is a little bit more involved. If the write operation originated
from an \gls{SDS} focussed on a single client-\gls{SDS}, the write action must
also be relayed to the actual device. If the write originated from an \gls{SDS}
focussed the devices or on one device only, nothing needs to be done. The
notification predicate determines whether a watcher gets a notification update.

\begin{lstlisting}[label={lst:actualdev},%
	caption={Device \gls{SDS}}]
deviceStore :: RWShared (Maybe (MTaskDevice, Int)) [MTaskDevice] [MTaskDevice]
deviceStore = SDSSource {SDSSource | name="deviceStore", read = realRead, write= realWrite}
where
	realRead :: (Maybe (MTaskDevice,Int)) *IWorld -> (MaybeError TaskException [MTaskDevice], *IWorld)
	realRead p iw = read realDeviceStore iw

	realWrite :: (Maybe (MTaskDevice,Int)) [MTaskDevice] *IWorld -> (MaybeError TaskException (SDSNotifyPred (Maybe (MTaskDevice,Int))), *IWorld)
	realWrite mi w iw
	# (merr, iw) = write w realDeviceStore iw
	| isError merr || isNothing mi = (merr $> notifyPred mi, iw)
	# (Just (dev, ident)) = mi
	| ident == -1 = (merr $> notifyPred mi, iw)
	= case find ((==)dev) w of
		Nothing = (Error $ exception "Device lost", iw)
		Just {deviceShares} = case find (\d->d.identifier == ident) deviceShares of
			Nothing = (Error $ exception "Share lost", iw)
			Just s = case sendMessagesIW [MTUpd ident s.MTaskShare.value] dev iw of
				(Error e, iw) = (Error e, iw)
				(Ok _, iw) = (Ok $ notifyPred mi, iw)

	notifyPred :: (Maybe (MTaskDevice, Int)) (Maybe (MTaskDevice, Int)) -> Bool
	notifyPred Nothing Nothing = True    // Global watcher looking at a global event
	notifyPred Nothing (Just _) = False  // Global watcher looking at a local event
	notifyPred (Just _) Nothing = False  // Local watcher looking at a global event
	// Local device watcher looking at a local event
	notifyPred (Just (d1, -1)) (Just (d2, _)) = d1 == d2
	// Local share watcher looking at a local share event
	notifyPred (Just (d1, i1)) (Just (d2, i2)) = d1 == d2 && i1 == i2

	realDeviceStore :: Shared [MTaskDevice]
	realDeviceStore = sharedStore "mTaskDevices" []
\end{lstlisting}

\subsubsection{Global \glspl{SDS}}
Accessing the global \gls{SDS} is just a matter of focussing the
\CI{deviceStore} with the \CI{Nothing} parameter as follows:

\begin{lstlisting}[caption={Global \gls{SDS}}]
deviceStoreNP :: Shared [MTaskDevice]
deviceStoreNP = sdsFocus Nothing deviceStore
\end{lstlisting}

\subsubsection{Local \glspl{SDS}}
Accessing a single device can be done using the \CI{mapReadWrite} function.
Since device comparison is shallow, the device that is given is allowed to be
an old version. The identification of devices is solely done on the name of the
channels and is unique throughout the system. The implementation is as follows:

\begin{lstlisting}[caption={Local \gls{SDS}}]
deviceShare :: MTaskDevice -> Shared MTaskDevice
deviceShare d = mapReadWriteError
	( \ds->case find ((==)d) of
		Nothing = exception "Device lost"
		Just d = Ok d)
	, \w ds->case splitWith ((==)d) ds of
		([], _) = Error $ exception "Device lost"
		([_:_], ds) = Ok $ Just [w:ds])
	$ sdsFocus (Just (d, -1)) deviceStore
\end{lstlisting}

\subsubsection{Local-\gls{SDS} specific \glspl{SDS}}
A single \gls{SDS} on a single device can be accessed using the \CI{shareShare}
function. This function focusses the real big \gls{SDS} on a single \gls{SDS}
and uses the \CI{mapReadWrite} functions to serve the correct part of the
information.

\begin{lstlisting}[caption={Local \gls{SDS}}]
shareShare :: MTaskDevice MTaskShare -> Shared BCValue
shareShare dev share = sdsFocus ()
	$ mapReadWriteError (read, write)
	$ sdsFocus (Just (dev, share.identifier))
	$ deviceStore
where
	read :: [MTaskDevice] -> MaybeError TaskException BCValue
	read devs = case find ((==)dev) devs of
		Nothing = exception "Device lost"
		Just d = case find ((==)share) d.deviceShares of
			Nothing = exception "Share lost"
			Just s = Ok s.MTaskShare.value
	
	write :: BCValue [MTaskDevice] -> MaybeError TaskException (Maybe [MTaskDevice])
	write val devs = case partition ((==)dev) devs of
		([], _) = Error $ exception "Device doesn't exist anymore"
		([_,_:_], _) = Error $ exception "Multiple matching devices"
		([d=:{deviceShares}], devs) = case partition ((==)share) deviceShares of
			([], _) = Error $ exception "Share doesn't exist anymore"
			([_,_:_], _) = Error $ exception "Multiple matching shares"
			([s], shares) = Ok $ Just [{MTaskDevice | d & 
				deviceShares=[{MTaskShare | s & value=val}:shares]}:devs]
\end{lstlisting}
