Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
hovsep committed Nov 4, 2024
1 parent 25ce5f1 commit 22bb4a7
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 44 deletions.
86 changes: 42 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

<div align="center">
<img src="./assets/img/logo.png" width="200" height="200" alt="f-mesh"/>
<h1>f-mesh</h1>
Expand All @@ -8,7 +7,7 @@

<h1>What is it?</h1>
<p>F-Mesh is a simplistic FBP-inspired framework in Go.
It allows you to express your program as a mesh of interconnected components.
It allows you to express your program as a mesh of interconnected components (or more formally as computational graph).
You can think of it as a simple functions orchestrator.
</p>
<h3>Main concepts:</h3>
Expand All @@ -23,63 +22,62 @@ You can think of it as a simple functions orchestrator.
<li>On each activation cycle the framework does same things: activates all the components ready for activation, flushes the data through pipes and disposes input <b>Signals (the data chunks flowing between components)</b></li>
<li>Ports and pipes are type agnostic, any data can be transferred or aggregated on any port</li>
<li>The framework works in discrete time, not it wall time. The quant of time is 1 activation cycle, which gives you "logical parallelism" out of the box</li>
<li>F-Mesh is suitable for logical wireframing, simulation, functional-style computations and implementing simple concurrency patterns without using the concurrency primitives like channels or any sort of locks</li>
<li>F-Mesh is suitable for prototyping, simulation, functional-style computations and implementing concurrency patterns without using the concurrency primitives like channels or any sort of locks</li>
</ul>

<h1>What it is not?</h1>
<p>F-mesh is not a classical FBP implementation, and it is not fully async. It does not support long-running components or wall-time events (like timers and tickers)</p>
<p>The framework is not suitable for implementing complex concurrent systems</p>


<h2>Example:</h2>

```go
// Create f-mesh
fm := fmesh.New("hello world").
WithComponents(
component.New("concat").
WithInputs("i1", "i2").
WithOutputs("res").
WithActivationFunc(func(inputs port.Collection, outputs port.Collection) error {
word1 := inputs.ByName("i1").Signals().FirstPayload().(string)
word2 := inputs.ByName("i2").Signals().FirstPayload().(string)
fm := fmesh.New("hello world").
WithComponents(
component.New("concat").
WithInputs("i1", "i2").
WithOutputs("res").
WithActivationFunc(func(inputs *port.Collection, outputs *port.Collection) error {
word1 := inputs.ByName("i1").FirstSignalPayloadOrDefault("").(string)
word2 := inputs.ByName("i2").FirstSignalPayloadOrDefault("").(string)

outputs.ByName("res").PutSignals(signal.New(word1 + word2))
return nil
}),
component.New("case").
WithInputs("i1").
WithOutputs("res").
WithActivationFunc(func(inputs port.Collection, outputs port.Collection) error {
inputString := inputs.ByName("i1").Signals().FirstPayload().(string)
outputs.ByName("res").PutSignals(signal.New(word1 + word2))
return nil
}),
component.New("case").
WithInputs("i1").
WithOutputs("res").
WithActivationFunc(func(inputs *port.Collection, outputs *port.Collection) error {
inputString := inputs.ByName("i1").FirstSignalPayloadOrDefault("").(string)

outputs.ByName("res").PutSignals(signal.New(strings.ToTitle(inputString)))
return nil
})).
.WithConfig(fmesh.Config{
ErrorHandlingStrategy: fmesh.StopOnFirstErrorOrPanic,
CyclesLimit: 10,
})
outputs.ByName("res").PutSignals(signal.New(strings.ToTitle(inputString)))
return nil
})).
WithConfig(fmesh.Config{
ErrorHandlingStrategy: fmesh.StopOnFirstErrorOrPanic,
CyclesLimit: 10,
})

fm.Components().ByName("concat").Outputs().ByName("res").PipeTo(
fm.Components().ByName("case").Inputs().ByName("i1"),
)
fm.Components().ByName("concat").Outputs().ByName("res").PipeTo(
fm.Components().ByName("case").Inputs().ByName("i1"),
)

// Init inputs
fm.Components().ByName("concat").Inputs().ByName("i1").PutSignals(signal.New("hello "))
fm.Components().ByName("concat").Inputs().ByName("i2").PutSignals(signal.New("world !"))
// Init inputs
fm.Components().ByName("concat").Inputs().ByName("i1").PutSignals(signal.New("hello "))
fm.Components().ByName("concat").Inputs().ByName("i2").PutSignals(signal.New("world !"))

// Run the mesh
_, err := fm.Run()
// Run the mesh
_, err := fm.Run()

// Check for errors
if err != nil {
fmt.Println("F-Mesh returned an error")
os.Exit(1)
}
// Check for errors
if err != nil {
fmt.Println("F-Mesh returned an error")
os.Exit(1)
}

//Extract results
results := fm.Components().ByName("case").Outputs().ByName("res").Signals().FirstPayload()
fmt.Printf("Result is :%v", results)
//Extract results
results := fm.Components().ByName("case").Outputs().ByName("res").FirstSignalPayloadOrNil()
fmt.Printf("Result is :%v", results)
```

<h2>Version 0.1.0 coming soon</h2>
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package integration_tests

import (
"fmt"
"github.com/hovsep/fmesh"
"github.com/hovsep/fmesh/component"
"github.com/hovsep/fmesh/cycle"
"github.com/hovsep/fmesh/port"
"github.com/hovsep/fmesh/signal"
"github.com/stretchr/testify/assert"
"os"
"strings"
"testing"
)

Expand Down Expand Up @@ -70,3 +73,55 @@ func Test_Math(t *testing.T) {
})
}
}

func Test_Readme(t *testing.T) {
t.Run("readme test", func(t *testing.T) {
fm := fmesh.New("hello world").
WithComponents(
component.New("concat").
WithInputs("i1", "i2").
WithOutputs("res").
WithActivationFunc(func(inputs *port.Collection, outputs *port.Collection) error {
word1 := inputs.ByName("i1").FirstSignalPayloadOrDefault("").(string)
word2 := inputs.ByName("i2").FirstSignalPayloadOrDefault("").(string)

outputs.ByName("res").PutSignals(signal.New(word1 + word2))
return nil
}),
component.New("case").
WithInputs("i1").
WithOutputs("res").
WithActivationFunc(func(inputs *port.Collection, outputs *port.Collection) error {
inputString := inputs.ByName("i1").FirstSignalPayloadOrDefault("").(string)

outputs.ByName("res").PutSignals(signal.New(strings.ToTitle(inputString)))
return nil
})).
WithConfig(fmesh.Config{
ErrorHandlingStrategy: fmesh.StopOnFirstErrorOrPanic,
CyclesLimit: 10,
})

fm.Components().ByName("concat").Outputs().ByName("res").PipeTo(
fm.Components().ByName("case").Inputs().ByName("i1"),
)

// Init inputs
fm.Components().ByName("concat").Inputs().ByName("i1").PutSignals(signal.New("hello "))
fm.Components().ByName("concat").Inputs().ByName("i2").PutSignals(signal.New("world !"))

// Run the mesh
_, err := fm.Run()

// Check for errors
if err != nil {
fmt.Println("F-Mesh returned an error")
os.Exit(1)
}

//Extract results
results := fm.Components().ByName("case").Outputs().ByName("res").FirstSignalPayloadOrNil()
fmt.Printf("Result is :%v", results)
assert.Equal(t, "HELLO WORLD !", results)
})
}

0 comments on commit 22bb4a7

Please sign in to comment.