1
0
Fork 0

Initial commit

This commit is contained in:
Gregory Eremin 2014-08-24 19:56:55 +07:00
commit 509f281f72
No known key found for this signature in database
GPG Key ID: 5EFA427EEC26E86C
11 changed files with 337 additions and 0 deletions

17
calculate.go Normal file
View File

@ -0,0 +1,17 @@
package main
import (
"code.google.com/p/go.net/context"
"github.com/localhots/yeast/core"
)
func main() {
chain, ok := core.NewChain("calculate")
if !ok {
println("Bad chain: calculate")
return
}
ctx := context.Background()
core.ProcessChain(ctx, chain)
}

22
config/chains.json Normal file
View File

@ -0,0 +1,22 @@
{
"calculate": {
"s": [
"uuid",
"input_from_flag",
{
"p": [
"power2",
"power3",
"power5"
]
},
"aggregator",
"logger",
{
"d": [
"sleep"
]
}
]
}
}

125
core/chain_processor.go Normal file
View File

@ -0,0 +1,125 @@
package core
import (
"encoding/json"
"io/ioutil"
"reflect"
"sync"
"code.google.com/p/go.net/context"
)
func NewChain(name string) (chain interface{}, ok bool) {
chains := readChains()
chain, ok = chains[name]
return
}
func ProcessChain(ctx context.Context, chain interface{}) context.Context {
ctx = processSequentialChain(ctx, []interface{}{chain})
return ctx
}
func processSequentialChain(ctx context.Context, chain []interface{}) context.Context {
for _, link := range chain {
val := reflect.ValueOf(link)
switch val.Kind() {
case reflect.Map:
lmap := link.(map[string]interface{})
if subchain, ok := lmap["s"]; ok {
ctx = processSequentialChain(ctx, subchain.([]interface{}))
} else if subchain, ok := lmap["p"]; ok {
ctx = processParallelChain(ctx, subchain.([]interface{}))
} else if subchain, ok := lmap["d"]; ok {
go processSequentialChain(ctx, subchain.([]interface{}))
}
case reflect.String:
unitName := val.String()
unit, ok := Units[unitName]
if !ok {
panic("Unknown unit: " + unitName)
}
// Execution of a unit
ctx = unit(ctx)
default:
panic("Unexpected chain element: " + val.Kind().String())
}
}
return ctx
}
func processParallelChain(ctx context.Context, chain []interface{}) context.Context {
var (
wg sync.WaitGroup
contexts = make(chan context.Context, len(chain))
finished = make(chan struct{})
)
for _, link := range chain {
val := reflect.ValueOf(link)
switch val.Kind() {
case reflect.Map:
lmap := link.(map[string]interface{})
if subchain, ok := lmap["s"]; ok {
wg.Add(1)
go func(ctx context.Context) {
contexts <- processSequentialChain(ctx, subchain.([]interface{}))
wg.Done()
}(ctx)
} else if subchain, ok := lmap["p"]; ok {
wg.Add(1)
go func(ctx context.Context) {
contexts <- processParallelChain(ctx, subchain.([]interface{}))
wg.Done()
}(ctx)
} else if subchain, ok := lmap["d"]; ok {
go processSequentialChain(ctx, subchain.([]interface{}))
}
case reflect.String:
unitName := val.String()
unit, ok := Units[unitName]
if !ok {
panic("Unknown unit: " + unitName)
}
// Execution of a unit
wg.Add(1)
go func(ctx context.Context) {
contexts <- unit(ctx)
wg.Done()
}(ctx)
default:
panic("Unexpected chain element: " + val.Kind().String())
}
}
go func() {
wg.Wait()
finished <- struct{}{}
}()
ctx = context.WithValue(ctx, "parallel_contexts", contexts)
ctx = context.WithValue(ctx, "parallel_finished", finished)
return ctx
}
func readChains() map[string]interface{} {
b, err := ioutil.ReadFile("config/chains.json")
if err != nil {
panic(err)
}
var chains map[string]interface{}
if err := json.Unmarshal(b, &chains); err != nil {
panic(err)
}
return chains
}

28
core/units.go Normal file
View File

@ -0,0 +1,28 @@
package core
import (
"code.google.com/p/go.net/context"
"github.com/localhots/yeast/units/aggregator"
"github.com/localhots/yeast/units/input"
"github.com/localhots/yeast/units/logger"
"github.com/localhots/yeast/units/power"
"github.com/localhots/yeast/units/sleep"
"github.com/localhots/yeast/units/uuid"
)
type (
UnitsDict map[string]func(context.Context) context.Context
)
var (
Units = UnitsDict{
"aggregator": aggregator.Call,
"logger": logger.Call,
"power2": power.Power2,
"power3": power.Power3,
"power5": power.Power5,
"input_from_flag": input.FromFlag,
"sleep": sleep.Call,
"uuid": uuid.Call,
}
)

22
tools/parallel.go Normal file
View File

@ -0,0 +1,22 @@
package tools
import (
"code.google.com/p/go.net/context"
)
func SyncronizeParallelChain(ctx context.Context, fn func(context.Context)) {
var (
pcontexts = ctx.Value("parallel_contexts").(chan context.Context)
pfinished = ctx.Value("parallel_finished").(chan struct{})
working = true
)
for len(pcontexts) > 0 || working {
select {
case pctx := <-pcontexts:
fn(pctx)
case <-pfinished:
working = false
}
}
}

View File

@ -0,0 +1,22 @@
package aggregator
import (
"fmt"
"code.google.com/p/go.net/context"
"github.com/localhots/yeast/tools"
"github.com/localhots/yeast/units/power"
)
func Call(ctx context.Context) context.Context {
results := []string{}
tools.SyncronizeParallelChain(ctx, func(ctx context.Context) {
r := ctx.Value("power_result").(power.PowerResult)
results = append(results, fmt.Sprintf("%d ^ %d = %d", r.Num, r.Power, r.Result))
})
ctx = context.WithValue(ctx, "power_results", results)
return ctx
}

17
units/input/cli.go Normal file
View File

@ -0,0 +1,17 @@
package input
import (
"flag"
"code.google.com/p/go.net/context"
)
func FromFlag(ctx context.Context) context.Context {
var num int
flag.IntVar(&num, "num", 0, "Pass this number")
flag.Parse()
ctx = context.WithValue(ctx, "num", num)
return ctx
}

20
units/logger/logger.go Normal file
View File

@ -0,0 +1,20 @@
package logger
import (
"fmt"
"code.google.com/p/go.net/context"
)
func Call(ctx context.Context) context.Context {
results := ctx.Value("power_results").([]string)
id := ctx.Value("id").(string)
fmt.Println("Calculation result", id)
fmt.Println("Power results are:")
for _, r := range results {
fmt.Println(r)
}
return ctx
}

37
units/power/power.go Normal file
View File

@ -0,0 +1,37 @@
package power
import (
"code.google.com/p/go.net/context"
)
type (
PowerResult struct {
Num int
Power int
Result int
}
)
func Power2(ctx context.Context) context.Context {
v := ctx.Value("num").(int)
res := PowerResult{Num: v, Power: 2, Result: v * v}
ctx = context.WithValue(ctx, "power_result", res)
return ctx
}
func Power3(ctx context.Context) context.Context {
v := ctx.Value("num").(int)
res := PowerResult{Num: v, Power: 3, Result: v * v * v}
ctx = context.WithValue(ctx, "power_result", res)
return ctx
}
func Power5(ctx context.Context) context.Context {
v := ctx.Value("num").(int)
res := PowerResult{Num: v, Power: 5, Result: v * v * v * v * v}
ctx = context.WithValue(ctx, "power_result", res)
return ctx
}

15
units/sleep/sleep.go Normal file
View File

@ -0,0 +1,15 @@
package sleep
import (
"fmt"
"time"
"code.google.com/p/go.net/context"
)
func Call(ctx context.Context) context.Context {
fmt.Println("Going into sleep")
time.Sleep(5 * time.Second)
fmt.Println("Woke up")
return ctx
}

12
units/uuid/uuid.go Normal file
View File

@ -0,0 +1,12 @@
package uuid
import (
"code.google.com/p/go-uuid/uuid"
"code.google.com/p/go.net/context"
)
func Call(ctx context.Context) context.Context {
ctx = context.WithValue(ctx, "id", uuid.New())
return ctx
}