Commit f87534e3 authored by Bas Lijnse's avatar Bas Lijnse

Tweaked the utility functions for creating startable tasks to reduce the need...

Tweaked the utility functions for creating startable tasks to reduce the need to pass default parameters in the common cases.
parent 6de0df39
Pipeline #13102 passed with stage
in 10 minutes and 45 seconds
......@@ -14,36 +14,45 @@ You can specify different tasks to be started through different URL paths, or yo
In this guide we will show you how to do this.
## Starting different tasks in one application ##
If we want to start different tasks by accessing different URLs we need to specify which URLs correspond to which tasks.
The `doTask` function is overloaded. It can be used with everything that is `Startable`.
If we want to start different tasks by accessing different URLs we need to specify which URLs correspond to which tasks. This also possible with `doTasks`.
The `doTasks` function is overloaded. It can be used with everything that is `Startable`.
There is an instance of `Startable` for `Task a` which is used in the simple case.
If we want to use `doTasks` with multiple tasks that can have different types we have to create a value that
If we want to use `doTasks` with multiple tasks that can have different types, we have to create a value that
wraps those tasks and groups them together.
We can do this as follows:
We do this as follows:
```Clean
taska = viewInformation () [] "Hello, world"
taskb = viewInformation () [] 42
Start world = doTasks
[onRequest "/ta" (const taska)
,onRequest "/tb" (const taskb)
]
[onRequest "/ta" taska
,onRequest "/tb" taskb
] world
```
The `onRequest` function takes a function that computes a task from an HTTP request (hence the `const` in the example) and wraps it together with the URL path as a `StartableTask` value.
The `onRequest` function takes a task and wraps it together with the URL path as a `StartableTask` value.
If you need the information from the HTTP request to compute the task, you can use `onRequestFromRequest`, which takes a function of type `HTTPRequest -> Task a` instead.
There is an instance of `Startable` for `[StartableTask]`.
This makes it possible to specify a heterogeneous list of tasks with different types that can be started by requesting different URLs. In most cases you don't need the HTTP request, but it can be useful.
## Starting tasks when the application starts ##
Some applications contain tasks that don't need any user interaction and should be started immediately.
For those cases there is the `onStartup` function which also wraps a task as `StartableTask` value.
Tasks that are wrapped this way are created when the iTask program starts and are not directly bound to any user or client. The other argument is a set of `TaskAttributes`.
This is initial meta-data that you can use to make it possible to identify the task instance.
Because these tasks are not directly attached to a client when they are created, this makes it possible to find and attach them later.
Tasks that are wrapped this way are created when the iTask program starts and are not directly bound to any user or client.
The following example shows a combination of an initialization task that is started when the application is started and another that can be started through the web.
```Clean
Start world = doTasks
[onStartup defaultValue initDatabase
,onRequest "/" (const browseDatabase)
]
[onStartup initDatabase
,onRequest "/" browseDatabase
] world
```
These tasks are not directly attached to a client when they are created. For a database initialization this may not be necessary, but sometimes you may want to attach them later.
In those cases you can use `onStartupWithAttributes`. This version takes another argument of type `TaskAttributes`. It lets you set the initial meta-data of the tasks, so you can identify the task instance.
This makes it possible to find and attach the task later.
## Advanced patterns ##
If you create frameworks for similar types of applications you can also create an instance of `Startable` for a type of your own. This lets you abstract from tasks that are always available in a certain type of application.
For example, the `iTasks.Extensions.Admin.WorkflowAdmin` extension defines the type `WorkflowCollection` which is `Startable`. Values of this type contain a set of tasks with names and descriptions.
This way, when you create an application using `WorkflowCollection` it initializes a database with those wrapped tasks, called workflows, on startup. It also adds a generic task that lets you login and choose which of those workflows to work on.
......@@ -36,10 +36,10 @@ import Incidone.DeviceBased.Tablet
Start :: *World -> *World
Start world = doTasks
[onRequest "/" (\_ -> ccPerson)
,onRequest "/wall" (\_ -> viewVideoWallContent)
,onRequest "/wall-control" (\_ -> selectVideoWallContent)
,onRequest "/exercise-control" (\_ -> controlExercise)
[onRequest "/" ccPerson
,onRequest "/wall" viewVideoWallContent
,onRequest "/wall-control" selectVideoWallContent
,onRequest "/exercise-control" controlExercise
] world
where
//Main task for command center operators
......
......@@ -11,22 +11,22 @@ import C2.Apps.ShipAdventure.Core, C2.Apps.ShipAdventure.Types, C2.Apps.ShipAdve
Start :: *World -> *World
Start world = doTasks
[onStartup defaultValue importDemoUsers
,onStartup defaultValue importDemoUsersFlow
,onStartup defaultValue (installWorkflows myTasks)
,onRequest "/" (\_ -> ccMain registerTasks continuousTasks alwaysOnTasks optionalTasks <<@ (Title "C2 System"))
,onRequest "/tonic" (\_ -> tonicDashboard [])
,onRequest "/debug" (\_ -> showDebug)
,onRequest "/adventure" (\_ -> loginAndManageWork "Adventure")
,onRequest "/alarm" (\_ -> setSectionDetectors)
,onRequest "/log" (\_ -> showLog)
//,onRequest "/devices" (\_ -> manageDevices True)
,onRequest "/editor" (\_ -> shipEditorTabs)
,onRequest "/changeFire" (\_ -> changeFireScript)
,onRequest "/changeFlood" (\_ -> changeFloodScript)
,onRequest "/changeSmoke" (\_ -> changeSmokeScript)
,onRequest "/doffMap" (\_ -> dOffMap)
,onRequest "/test" (\_ -> editMaps2D)
[onStartup importDemoUsers
,onStartup importDemoUsersFlow
,onStartup (installWorkflows myTasks)
,onRequest "/" (ccMain registerTasks continuousTasks alwaysOnTasks optionalTasks <<@ (Title "C2 System"))
,onRequest "/tonic" (tonicDashboard [])
,onRequest "/debug" showDebug
,onRequest "/adventure" (loginAndManageWork "Adventure")
,onRequest "/alarm" (setSectionDetectors)
,onRequest "/log" showLog
//,onRequest "/devices" (manageDevices True)
,onRequest "/editor" shipEditorTabs
,onRequest "/changeFire" changeFireScript
,onRequest "/changeFlood" changeFloodScript
,onRequest "/changeSmoke" changeSmokeScript
,onRequest "/doffMap" dOffMap
,onRequest "/test" editMaps2D
] world
editMaps2D :: Task Maps2D
......
......@@ -8,8 +8,8 @@ import iTasks.UI.Definition, iTasks.Extensions.Admin.UserAdmin
Start :: *World -> *World
Start world = doTasks
[onStartup defaultValue (installWorkflows workflows)
,onRequest "/" (\_ -> loginAndManageWork "The Taxman")
[onStartup (installWorkflows workflows)
,onRequest "/" (loginAndManageWork "The Taxman")
] world
workflows :: [Workflow]
......
......@@ -10,8 +10,8 @@ startMultiUserTasks workflows tasks world
] tasks world
startTask taskList tasks world
= doTasks [ onStartup defaultValue (installWorkflows taskList)
, onRequest "/" (const browseExamples)
= doTasks [ onStartup (installWorkflows taskList)
, onRequest "/" browseExamples
: tasks
] world
where
......
......@@ -36,8 +36,13 @@ import iTasks.WF.Definition
:: TaskWrapper = E.a: TaskWrapper (Task a) & iTask a
//Utility functions for creating collections of startable tasks
onRequest :: String (HTTPRequest -> Task a) -> StartableTask | iTask a
onStartup :: TaskAttributes (Task a) -> StartableTask | iTask a
//Common cases:
onStartup :: (Task a) -> StartableTask | iTask a
onRequest :: String (Task a) -> StartableTask | iTask a
//Less common cases:
onStartupWithAttributes :: (Task a) TaskAttributes -> StartableTask | iTask a
onRequestFromRequest :: String (HTTPRequest -> Task a) -> StartableTask | iTask a
publish :== onRequest //Backwards compatibility
......
......@@ -135,11 +135,17 @@ where
("Specify the folder containing the sapl files\ndefault: " +++ defaults.saplDirPath)
]
onRequest :: String (HTTPRequest -> Task a) -> StartableTask | iTask a
onRequest path task = WebTask {WebTask|path = path, task = WebTaskWrapper task}
onStartup :: (Task a) -> StartableTask | iTask a
onStartup task = StartupTask {StartupTask|attributes = defaultValue, task = TaskWrapper task}
onStartup :: TaskAttributes (Task a) -> StartableTask | iTask a
onStartup attributes task = StartupTask {StartupTask|attributes = attributes, task = TaskWrapper task}
onRequest :: String (Task a) -> StartableTask | iTask a
onRequest path task = WebTask {WebTask|path = path, task = WebTaskWrapper (const task)}
onStartupWithAttributes :: (Task a) TaskAttributes -> StartableTask | iTask a
onStartupWithAttributes task attributes = StartupTask {StartupTask|attributes = attributes, task = TaskWrapper task}
onRequestFromRequest :: String (HTTPRequest -> Task a) -> StartableTask | iTask a
onRequestFromRequest path task = WebTask {WebTask|path = path, task = WebTaskWrapper task}
class Startable a
where
......@@ -148,15 +154,15 @@ where
instance Startable (Task a) | iTask a //Default as web task
where
toStartable task =
[onStartup defaultValue viewWebServerInstructions
,onRequest "/" (const task)
[onStartup viewWebServerInstructions
,onRequest "/" task
]
instance Startable (HTTPRequest -> Task a) | iTask a //As web task
where
toStartable task =
[onStartup defaultValue viewWebServerInstructions
,onRequest "/" task
[onStartup viewWebServerInstructions
,onRequestFromRequest "/" task
]
instance Startable StartableTask
......
......@@ -96,8 +96,8 @@ allowedPersistentWorkflows = mapRead (\wfs -> [wf \\ wf=:{Workflow|transient} <-
instance Startable WorkflowCollection
where
toStartable {WorkflowCollection|name,workflows} =
[onStartup defaultValue (installWorkflows workflows)
,onRequest "/" (const (loginAndManageWork name))
[onStartup (installWorkflows workflows)
,onRequest "/" (loginAndManageWork name)
]
installWorkflows :: ![Workflow] -> Task ()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment