This repository has been archived by the owner on Sep 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Foreman.coffee
138 lines (123 loc) · 3.1 KB
/
Foreman.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Foreman.coffee
# SFZILabs 2020
Future = require 'fluture'
Fluent = require('fluenture').fluent
Priorities =
Minor: 1
Major: 2
Critical: 3
Difficulty =
Free: 0
Easy: 1
Varying: 2
Hard: 3
class Prerequisite
isPrereq: true
constructor: (@Priority = Priorities.Minor, @Name) ->
requestAgent: (@NeedAgent = true) ->
suggest: -> [] # Array of prerequisites and actions
class Action
constructor: (@Difficulty = Difficulty.Varying, @Name) ->
@Requirements = []
@State = {}
require: (P) ->
P.Parent = @
@Requirements.push P
init: -> # Add requirements sync
setState: (@State = {}) ->
setAgent: (@Agent) ->
getDepth: ->
if @Parent
return 1 + @Parent.getDepth()
return 0
choose: (Actions) ->
Lowest = undefined
Choice = undefined
for A in Actions
if Lowest != undefined
if A.Difficulty < Lowest
Lowest = A.Difficulty
Choice = A
else
Choice = A
Lowest = A.Difficulty
Choice
resolve: -> # Run requirements
Fluent new Future (Reject, Resolve) =>
Index = -1
Current = ->
Next = =>
Current = ->
Index++
P = @Requirements[Index]
if P #
if P.isPrereq
P.Agent = @Agent if P.NeedAgent
A = P.suggest().sort (a, b) -> a.Difficulty - b.Difficulty
# Try all prerequisites
PotentialActions = Fluent Future.reject()
if not A.length
Reject 'no solution for '+P.Name
else #A.start(@State).fork Reject, Next
console.log 'trying solutions of',P.Name,'for',@Name
while A.length > 0
X = A.shift()
if X.isPrereq # utils any
a = 1
console.log ' '+X.Name
PotentialActions = PotentialActions.alt X.start @State, @Agent
PotentialActions = PotentialActions.alt Future.reject 'all solutions failed for '+P.Name
Current = PotentialActions.fork Reject, Next
else # action, init,
console.log 'running',P.Name
Current = P.start(@State, @Agent).fork Reject, Next
else Resolve() # Completed all
Next()
->
Next = ->
Current()
execute: -> Fluent new Future.resolve()
start: (S, A) ->
@setState S
@setAgent A
@init()
@resolve().and @execute()
###
ACTION:
Can have prerequisites
Can require other actions
All children (actions and prereqs) must be satisfied before 'execute' is called
Flow:
Run method 'init', all our prereqs and actions are added
Run method 'start', this returns a monadic future
Fork the future
Future runs method 'resolve', this calls init and then resolve on children.
Run our method 'execute' on future success, or reject with the last error
We are done, and our parent action (if any) continues
PREREQUISITE:
Can only suggest actions
Suggested actions can fail
###
EventEmitter = require 'events'
class Manager extends EventEmitter
constructor: (@Agent) ->
super()
@State = {
Managed: true
crafting: {}
}
schedule: (Action) ->
Done = =>
@emit 'done'
console.log 'Success'
Fail = (S) =>
@emit 'fail'
console.error 'Failure:',S.message
Action.start(@State, @Agent).fork Fail, Done
module.exports = {
Manager,
Prerequisite,
Action,
Priorities,
Difficulty
}