initial commit

This commit is contained in:
2023-07-17 18:07:44 +02:00
commit a2ea3209f1
4 changed files with 342 additions and 0 deletions

154
actions/actions.go Normal file
View File

@@ -0,0 +1,154 @@
package actions
import (
"fmt"
"sort"
"time"
)
type OptionMissingError struct {
optionName string
}
func (o OptionMissingError) Error() string {
return fmt.Sprintf("Error during config parsing: option %s could not be parsed.", o.optionName)
}
type Options map[string]interface{}
type ActionConfig struct {
Type string `json:"type"`
Options Options `json:"options"`
Stage int `json:"stage"`
}
type KillSwitchConfig struct {
Name string `json:"name"`
Type string `json:"type"`
Options Options `json:"options"`
Actions []ActionConfig `json:"actions"`
}
type Action interface {
Execute()
}
type Printer struct {
Message string
ActionChan chan bool
}
func (p Printer) Execute() {
fmt.Printf("Print action fires. Message: %s", p.Message)
p.ActionChan <- true
}
type TimeOut struct {
Duration time.Duration
ActionChan chan bool
}
func (t TimeOut) Execute() {
fmt.Printf("Waiting %d seconds\n", t.Duration/time.Second)
time.Sleep(t.Duration)
t.ActionChan <- true
}
type Stage struct {
Actions []Action
}
type StagedActions struct {
ActionChan chan bool
StageCount int
Stages []Stage
}
func (a StagedActions) Execute() {
for idx, stage := range a.Stages {
if idx < a.StageCount {
continue
}
fmt.Printf("Execute Stage %v\n", idx+1)
for actionidx, _ := range stage.Actions {
go stage.Actions[actionidx].Execute()
}
for range stage.Actions {
<-a.ActionChan
}
}
}
func NewPrint(config ActionConfig, c chan bool) (Action, error) {
opts := config.Options
message, ok := opts["message"]
if !ok {
return nil, OptionMissingError{"message"}
}
return Printer{fmt.Sprintf("%v", message), c}, nil
}
func NewTimeOut(config ActionConfig, c chan bool) (Action, error) {
opts := config.Options
duration, ok := opts["duration"]
if !ok {
return nil, OptionMissingError{"message"}
}
return TimeOut{time.Duration(duration.(float64)) * time.Second, c}, nil
}
func NewSingleAction(config ActionConfig, c chan bool) (Action, error) {
if config.Type == "Print" {
return NewPrint(config, c)
}
if config.Type == "TimeOut" {
return NewTimeOut(config, c)
}
return nil, fmt.Errorf("Error parsing config: Action with type %s does not exists", config.Type)
}
func NewAction(config []ActionConfig) (Action, error) {
if len(config) == 1 {
return NewSingleAction(config[0], make(chan bool))
}
sort.Slice(config, func(i, j int) bool {
return config[i].Stage < config[j].Stage
})
stagedActions := StagedActions{make(chan bool), 0, []Stage{}}
stageMap := make(map[int][]Action)
for _, actionCfg := range config {
newAction, err := NewSingleAction(actionCfg, stagedActions.ActionChan)
if err != nil {
return nil, err
}
val, exists := stageMap[actionCfg.Stage]
if !exists {
stageMap[actionCfg.Stage] = []Action{newAction}
continue
}
stageMap[actionCfg.Stage] = append(val, newAction)
}
for _, value := range stageMap {
stagedActions.Stages = append(stagedActions.Stages, Stage{value})
}
return stagedActions, nil
//return Action{}, fmt.Errorf("Error parsing config: Action with type %s does not exists", config.Type)
}

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module unknown.com/gokill
go 1.20

117
gokill.go Normal file
View File

@@ -0,0 +1,117 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"unknown.com/gokill/triggers"
)
func main() {
configFile := flag.String("c", "", "path to config file")
flag.Parse()
if *configFile == "" {
fmt.Println("No config file given. Use --help to show usage.")
//return
}
b := []byte(`
[
{
"type": "TimeOut",
"name": "custom timeout",
"options": {
"duration": 5
},
"actions": [
{
"type": "TimeOut",
"options": {
"duration": 4
},
"stage": 1
},
{
"type": "Print",
"options": {
"message": "shutdown -h now"
},
"stage": 1
},
{
"type": "Print",
"options": {
"message": "shutdown -h now"
},
"stage": 2
},
{
"type": "TimeOut",
"options": {
"duration": 4
},
"stage": 5
},
{
"type": "Print",
"options": {
"message": "shutdown -h now"
},
"stage": 4
},
{
"type": "Print",
"options": {
"message": "shutdown -h now"
},
"stage": 7
}
]
}
]
`)
var f []triggers.KillSwitchConfig
err := json.Unmarshal(b, &f)
if err != nil {
fmt.Println(err)
return
}
trigger, err := triggers.NewTrigger(f[0])
if err != nil {
fmt.Println(err)
return
}
trigger.Listen()
//stagedActions := actions.StagedActions{make(chan bool), 0, []actions.Stage{}}
//stageOne := actions.Stage{[]actions.Action{
// actions.Printer{"first action\n", stagedActions.ActionChan},
// actions.Printer{"second actiloo\n", stagedActions.ActionChan},
// actions.TimeOut{stagedActions.ActionChan},
//}}
//stageTwo := actions.Stage{[]actions.Action{
// actions.Printer{"third action\n", stagedActions.ActionChan},
// actions.TimeOut{stagedActions.ActionChan},
//}}
//stageThree := actions.Stage{[]actions.Action{
// actions.Printer{"four action\n", stagedActions.ActionChan},
// actions.Printer{"five action\n", stagedActions.ActionChan},
// actions.Printer{"six action\n", stagedActions.ActionChan},
//}}
//stagedActions.Stages = []actions.Stage{stageOne, stageTwo, stageThree}
//timeOut := triggers.NewTimeOut(2*time.Second, stagedActions)
//timeOut.Listen()
}

68
triggers/triggers.go Normal file
View File

@@ -0,0 +1,68 @@
package triggers
import (
"fmt"
"time"
"unknown.com/gokill/actions"
)
type Options map[string]interface{}
type KillSwitchConfig struct {
Name string `json:"name"`
Type string `json:"type"`
Options Options `json:"options"`
Actions []actions.ActionConfig `json:"actions"`
}
type Trigger interface {
Listen()
}
type TimeOut struct {
d time.Duration
action actions.Action
}
func (t TimeOut) Listen() {
fmt.Println("TimeOut listens")
time.Sleep(t.d)
fmt.Println("TimeOut fires")
t.action.Execute()
}
type OptionMissingError struct {
optionName string
}
func (o OptionMissingError) Error() string {
return fmt.Sprintf("Error during config parsing: option %s could not be parsed.", o.optionName)
}
// func NewTimeOut(d time.Duration, action actions.Action) TimeOut {
func NewTimeOut(config KillSwitchConfig) (TimeOut, error) {
opts := config.Options
duration, ok := opts["duration"]
if !ok {
return TimeOut{}, OptionMissingError{"duration"}
}
action, err := actions.NewAction(config.Actions)
if err != nil {
return TimeOut{}, err
}
return TimeOut{time.Duration(duration.(float64)) * time.Second, action}, nil
}
func NewTrigger(config KillSwitchConfig) (Trigger, error) {
if config.Type == "TimeOut" {
return NewTimeOut(config)
}
return nil, fmt.Errorf("Error parsing config: Trigger with type %s does not exists", config.Type)
}