Forráskód Böngészése

Added small explanations

* Fixed bug reading nil values
luis 7 éve
szülő
commit
a818a5bfde

+ 3 - 6
browser/vue-flow/package.json

@@ -6,7 +6,8 @@
   "license": "MIT",
   "private": true,
   "scripts": {
-    "docker": "docker build --rm -t hexasoftware.com:5000/flow-proto -f ./docker/Dockerfile .",
+    "docker":
+      "docker build --rm -t hexasoftware.com:5000/flow-proto -f ./docker/Dockerfile .",
     "docker-pull": "docker push hexasoftware.com:5000/flow-proto",
     "dev": "cross-env NODE_ENV=development webpack-dev-server --hot",
     "build": "cross-env NODE_ENV=production webpack --hide-modules"
@@ -14,11 +15,7 @@
   "dependencies": {
     "vue": "^2.5.11"
   },
-  "browserslist": [
-    "> 1%",
-    "last 2 versions",
-    "not ie <= 8"
-  ],
+  "browserslist": ["> 1%", "last 2 versions", "not ie <= 8"],
   "devDependencies": {
     "babel-core": "^6.26.0",
     "babel-eslint": "^8.2.1",

+ 6 - 1
browser/vue-flow/src/assets/dark-theme.css

@@ -2,9 +2,14 @@
   --header-background: #212121;
   --header-color: #eee;
   --background: #303030;
+  --background-transparent: rgba(48, 48, 48, 0.7);
   --background-secondary: #424242;
   --background-tertiary: #323232;
-  --normal: #eee;
+
+  /*--background-secondary: #424242;*/
+
+  /*--background-tertiary: #323232;*/
+  --normal: #aaa;
   --normal-secondary: #777;
 
   /* --primary: #f57c00 ; */

+ 32 - 0
browser/vue-flow/src/assets/default-theme.css

@@ -2,6 +2,7 @@
   --header-background: #113244;
   --header-color: #fff;
   --background: #f4f4f4;
+  --background-transparent: rgba(240, 240, 240, 0.9);
   --background-secondary: rgba(208, 208, 208, 1);
   --background-tertiary: rgba(188, 188, 188, 1);
   --normal: #333;
@@ -311,6 +312,37 @@ h3 {
   fill: var(--normal);
 }
 
+/*
+ * HX-MODAL
+ */
+.hx-modal__container {
+  background: var(--background-transparent);
+  color: var(--normal);
+  height: 70vh;
+  display: flex;
+  flex-flow: column;
+  overflow: hidden;
+}
+
+.hx-modal__header {
+  border-bottom: solid 1px rgba(150, 150, 150, 0.2);
+  flex-shrink: 0;
+  margin-bottom: 16px;
+}
+
+.hx-modal__body {
+  overflow-y: auto;
+  flex-grow: 1;
+  margin: 0;
+  padding: 0 20px !important;
+  padding: 20px;
+}
+
+.hx-modal__footer {
+  margin-top: 16px;
+  flex-shrink: 0;
+}
+
 /*
  * CHAT
  */

+ 100 - 0
browser/vue-flow/src/components/app-info.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="app-info">
+    <section class="app-info__section app-info--view">
+      <h4>Editor</h4>
+      <ul>
+        <li><b>Collaboration</b>: Using the same url address, others can join the session</li>
+        <li><b>Pan</b>: Drag with Middle Mouse or Ctrl+left mouse button</li>
+        <li><b>Zoom</b>: Mouse wheel up and down to zoom in and out</li>
+        <li><b>Reset</b>: Reset view by pressing on the reset button</li>
+      </ul>
+    </section>
+    <section class="app-info__section app-info--flow">
+      <h4>Flow:</h4>
+      <p>
+        A flow works by requesting the previous nodes the results of its operation, so the starting node will
+        be the node we want the result of, unattached nodes wont be executed
+      </p>
+      <p>
+
+        All nodes are Go functions.
+        here's an example of a Flow app with a node with a single output:
+        <a target="_blank" :href="'http://'+ location.host +'/c1.html'">sample1</a><br>
+        Every function can be registered including from external packages as shown in
+        <a target="_blank" :href="'http://'+ location.host +'/c2.html'">sample2</a><br>
+        Describing functions:
+        <a target="_blank" :href="'http://'+ location.host +'/c3.html'">sample3</a><br>
+
+      </p>
+      <ul>
+        <li><b>New Node</b>: Create a node by dragging a fn from left panel into area</li>
+        <li><b>Remove Node</b>: Middle click in a node to remove a node</li>
+        <li><b>Inspect node</b>: Double click on a node to get detailed information</li>
+        <li><b>Move Node</b>: Mouse click and drag</li>
+        <li><b>Links</b>: Press [shift] and Drag from a node/socket to a socket highlighted in green</li>
+        <li><b>Links(alternative)</b>: Toggle socket visualisation in the panel and Drag from a socket to a socket highlighted in green</li>
+        <li><b>Remove Link</b>: Simple click on the link when it turns red</li>
+      </ul>
+    </section>
+    <div class="app-info__section app-info__triggers">
+      <h4>Triggers</h4>
+      <p>
+        Triggers works when a node changes its status it will call the linked node, triggers will have filters
+        such as (finish, error, start), this will be useful to create CI pipelines by triggering different processes
+        (i.e: running a container to send an email informing the status of the build)
+      </p>
+    </div>
+
+    <h4>TODO:</h4>
+    <ul>
+      <li>UX/UI: create undoer</li>
+      <li>UX/UI: Special nodes with display capabilities (images,datatables,...)</li>
+      <li>UX/UI: Group nodes into a single box, exposing inputs and outputs</li>
+      <li>UX/UI: Implement touch</li>
+      <li>UX/UI: drop link in node to link to next compatible available input</li>
+      <li>Collaboration: Better concurrent editing/message passing (testing)</li>
+      <li>FlowPkg: Create training mechanism</li>
+      <li>FlowPkg: matrix pooling function example</li>
+    </ul>
+    <br>
+    <small>&copy; Luis Figueiredo (luisf@hexasoftware.com)</small>
+  </div>
+</template>
+<script>
+export default {
+
+  computed: {
+    location () {
+      console.log(window.location)
+      return window.location
+    }
+  }
+}
+</script>
+<style>
+.app-info {
+  flex:1;
+}
+
+.app-info--info {
+  font-size:14px;
+}
+
+.app-info__section h4 {
+  margin-top:20px;
+  margin-bottom:5px;
+  color: var(--primary);
+}
+
+.app-info__section p {
+  font-size:14px;
+  margin:5px 15px 15px 4px;
+  padding:20px 10px;
+  background: var(--background-secondary);
+}
+
+.app-info__section li {
+  padding:4px;
+}
+
+</style>

+ 3 - 2
browser/vue-flow/src/components/flow/editor.vue

@@ -2,6 +2,7 @@
   <div class="flow-container">
     <svg
       xmlns="http://www.w3.org/2000/svg"
+      xmlns:xhtml="http://www.w3.org/1999/xhtml"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       ref="svg"
       class="flow-view view"
@@ -45,7 +46,6 @@
           @triggerPointerDown="triggerPointerDown(n.id,...arguments)"
           @nodeDoubleClick="$emit('nodeDblClick',n)"
           @nodeRightClick="$refs.menu.open($event,n)"
-
         />
         <!-- mouse link-->
         <flow-link
@@ -116,7 +116,8 @@
   justify-content: center;
   margin:0;
   padding:14px;
-  color:#333;
+
+  /*color:#333;*/
 }
 
 .flow-container__info {

+ 4 - 2
browser/vue-flow/src/components/flow/node.vue

@@ -39,7 +39,6 @@
         v-bind="bodyProps"
       />
     </template>
-
     <!-- selection square -->
     <rect
       class="flow-node__selection"
@@ -150,8 +149,8 @@
 <script>
 import {mapGetters} from 'vuex'
 import FlowNodeActivity from './node-activity'
-
 import utils from '@/utils/utils'
+
 const shapeOpts = {
   'circle': {
     textWrap: 'any'
@@ -475,4 +474,7 @@ for hidden
   opacity:0.9;
 }
 
+canvas {
+  border: solid 1px #f00;
+}
 </style>

+ 78 - 92
browser/vue-flow/src/components/main.vue

@@ -1,100 +1,83 @@
 <template>
   <div class="flow-main" :class="{dark:dark}">
-    <div class="app-header">
-      Flow
-      <button @click="dark=!dark">{{ dark?'light':'dark' }}</button>
-    </div>
-    <div class="app-horizontal">
-      <div class="app-flow-container">
-        <div class="app-watermark">PROTOTYPE</div>
-        <div class="app-info">
-          <h4>HELP</h4>
-          <ul>
-            <li><b>Pan</b>: Drag with Middle Mouse or Ctrl+left mouse button</li>
-            <li><b>Zoom</b>: Mouse wheel up and down to zoom in and out</li>
-            <li><b>New Node</b>: Create a node by dragging a fn from left panel into area</li>
-            <li><b>Remove Node</b>: Middle click in a node to remove a node</li>
-            <li><b>Inspect node</b>: Double click on a node to get detailed information</li>
-            <li><b>Move Node</b>: Mouse click and drag</li>
-            <li><b>Links</b>: Press [shift] and Drag from a node/socket to a socket highlighted in green</li>
-            <li><b>Links(alternative)</b>: Toggle socket visualisation in the panel and Drag from a socket to a socket highlighted in green</li>
-            <li><b>Remove Link</b>: Simple click on the link when it turns red</li>
-          </ul>
-
-          <h4>TODO:</h4>
-          <ul>
-            <li>UX/UI: Undo changes</li>
-            <li>UX/UI: Special nodes with display capabilities (images,datatables,...)</li>
-            <li>UX/UI: Group nodes into a single box, exposing inputs and outputs</li>
-            <li>UX/UI: Implement touch</li>
-            <li>UX/UI: drop link in node to link to next compatible available input</li>
-            <li>Registry: Synchronize registry with server(GET)</li>
-            <li>Collaboration: Better concurrent editing/message passing (testing)</li>
-            <li>Collaboration: Improve document synchronization</li>
-            <li>FlowServer: Build the graph on the server and run</li>
-            <li>FlowPkg: Create training mechanism</li>
-            <li>FlowPkg: matrix pooling function example</li>
-          </ul>
-          <br>
-          <small>&copy; Luis Figueiredo (luisf@hexasoftware.com)</small>
+    <div class="app-content" :class="{'app-content--blur':helpModal}">
+      <div class="app-header">
+        Flow
+        <div>
+          <button @click="helpModal=true">?</button>
+          <button @click="dark=!dark">{{ dark?'light':'dark' }}</button>
         </div>
+      </div>
+      <div class="app-horizontal">
+        <div class="app-flow-container">
+          <div class="app-watermark">PROTOTYPE</div>
 
-        <!--:value="nodeData"
+          <!--:value="nodeData"
         @input="documentUpdate"-->
-        <hx-split
-          dir="horizontal"
-          :resizeable="true"
-          :split="funcsSize"
-          @onSplitResize="funcsSizeUpdate"
-
-        >
-          <div class="flow-panel__container">
-            <div class="flow-panel__selector">
-              <button :class="{active:panel=='palette'}" @click="panel='palette'">Funcs</button>
-              <button :class="{active:panel=='inspector'}" @click="panel='inspector';">Inspector</button>
+          <hx-split
+            dir="horizontal"
+            :resizeable="true"
+            :split="funcsSize"
+            @onSplitResize="funcsSizeUpdate"
+
+          >
+            <div class="flow-panel__container">
+              <div class="flow-panel__selector">
+                <button :class="{active:panel=='palette'}" @click="panel='palette'">Funcs</button>
+                <button :class="{active:panel=='inspector'}" @click="panel='inspector';">Inspector</button>
+              </div>
+              <transition name="fade">
+                <flow-funcs
+                  v-show="panel=='palette'"
+                  @toggleResizeable="funcsResizeable=!funcsResizeable"
+                  @toggleStickySockets="managerStickySockets=!managerStickySockets"
+                />
+              </transition>
+              <transition name="fade">
+                <flow-inspector
+                  ref="inspector"
+                  v-show="panel=='inspector'"
+                />
+              </transition>
             </div>
-            <transition name="fade">
-              <flow-funcs
-                v-show="panel=='palette'"
-                @toggleResizeable="funcsResizeable=!funcsResizeable"
-                @toggleStickySockets="managerStickySockets=!managerStickySockets"
-              />
-            </transition>
-            <transition name="fade">
-              <flow-inspector
-                ref="inspector"
-                v-show="panel=='inspector'"
-              />
-            </transition>
-          </div>
-          <flow-editor
-            ref="flowManager"
-            @nodeInspect="nodeInspectStart(...arguments)"
-            @nodeProcess="nodeProcess(...arguments)"
-            @nodeDblClick="nodeInspectStart(...arguments,true)"
-            @documentSave="documentSave"
-
-            width="100%"
-            height="100%"/>
-        </hx-split>
-      </div>
-      <div class="app-chat">
-        <app-chat/>
+            <flow-editor
+              ref="flowManager"
+              @nodeInspect="nodeInspectStart(...arguments)"
+              @nodeProcess="nodeProcess(...arguments)"
+              @nodeDblClick="nodeInspectStart(...arguments,true)"
+              @documentSave="documentSave"
+
+              width="100%"
+              height="100%"/>
+          </hx-split>
+        </div>
+        <div class="app-chat">
+          <app-chat/>
+        </div>
+        <flow-notifications/>
       </div>
-      <flow-notifications/>
     </div>
+    <hx-modal class="app-modal__info" v-if="helpModal" @close="helpModal=false">
+      <h4 slot="header">INFO</h4>
+      <app-info slot="body"/>
+      <div slot="footer">
+        <button class="primary-inverse" @click="helpModal=false">OK</button>
+      </div>
+
+    </hx-modal>
   </div>
 </template>
 <script>
 import {mapGetters, mapActions} from 'vuex'
-import AppChat from '@/components/chat'
 import FlowEditor from '@/components/flow/editor'
 import FlowPanzoom from '@/components/flow/panzoom'
 import FlowNotifications from '@/components/flow/notifications'
-import FlowFuncs from './panel-funcs'
 import FlowInspector from './panel-inspector'
+import FlowFuncs from './panel-funcs'
 import HxSplit from '@/components/shared/hx-split'
 import HxModal from '@/components/shared/hx-modal'
+import AppChat from '@/components/chat'
+import AppInfo from '@/components/app-info'
 import 'reset-css/reset.css'
 
 import '@/assets/dark-theme.css'
@@ -110,10 +93,12 @@ export default {
     FlowFuncs,
     HxSplit,
     HxModal,
-    AppChat
+    AppChat,
+    AppInfo
   },
   data () {
     return {
+      helpModal: false,
       panel: 'palette',
 
       funcsSize: '250px',
@@ -183,7 +168,19 @@ export default {
 .flow-main {
   height:100%;
   display:flex;
-  flex-direction: column;
+  flex-flow: column;
+}
+
+.app-content {
+  display:flex;
+  flex-flow:column;
+  flex-basis:100%;
+  flex:1;
+  transition: all var(--transition-speed);
+}
+
+.app-content--blur {
+  filter: blur(7px);
 }
 
 .app-flow-container {
@@ -208,17 +205,6 @@ export default {
   align-items: center;
 }
 
-.app-info {
-  opacity:0.5;
-  color: #aaa;
-  font-size:10px;
-  margin:20px;
-  padding:20px;
-  position:absolute;
-  right:0;
-  bottom:3%;
-}
-
 .flow-main .app-watermark {
   position:absolute;
   top:40%;

+ 9 - 7
browser/vue-flow/src/store/flow/default-registry.js

@@ -3,7 +3,7 @@ export default{
     categories: ['core'],
     output: {type: 'interface {}'},
     style: { color: '#686', shape: 'circle' },
-    props: {} // should be sent in the node
+    props: {'input': ''} // should be sent in the node
   },
   'Variable': {
     categories: ['core'],
@@ -11,12 +11,6 @@ export default{
     output: {type: 'interface {}'},
     style: { color: '#88a', shape: 'circle' }
   },
-  'Const': {
-    categories: ['core'],
-    output: {type: 'interface {}'},
-    style: { color: '#555' }
-    // , props: {value: ''}
-  },
   'Output': {
     categories: ['core'],
     inputs: [{type: 'interface {}'}],
@@ -32,5 +26,13 @@ export default{
     categories: ['flow-web'],
     output: {type: 'io.Writer'},
     style: {color: '#665'}
+  },
+  'Three': {
+    categories: ['flow-experiment'],
+    inputs: [{type: 'interface {}'}],
+    output: {type: 'interface {}'},
+    style: {color: '#592'},
+    experimental: true
+
   }
 }

+ 4 - 0
browser/vue-flow/yarn.lock

@@ -5611,6 +5611,10 @@ text-table@~0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
 
+three@^0.89.0:
+  version "0.89.0"
+  resolved "https://registry.yarnpkg.com/three/-/three-0.89.0.tgz#4442d819a6168871b8d2cb37ad12a24310c170f5"
+
 through2@^2.0.0:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"

+ 33 - 20
go/src/flow/operation.go

@@ -8,6 +8,7 @@ package flow
 import (
 	"errors"
 	"fmt"
+	"log"
 	"reflect"
 	"sync"
 )
@@ -60,7 +61,21 @@ func (o *operation) Set(data Data) {
 func (f *Flow) asTrigger(id string, fn executorFunc) executorFunc {
 	return func(ctx OpCtx, params ...Data) (Data, error) {
 		f.hooks.start(id)
-		res, err := fn(ctx, params...)
+
+		//panic recoverer, since nodes are not our functions
+		var err error
+		var res Data
+		func() {
+			defer func() {
+
+				if r := recover(); r != nil {
+					log.Println("Panic:", r)
+					err = fmt.Errorf("%v", r)
+				}
+			}()
+			res, err = fn(ctx, params...)
+		}()
+
 		if err != nil {
 			f.hooks.error(id, err)
 		} else {
@@ -75,14 +90,6 @@ func (f *Flow) asTrigger(id string, fn executorFunc) executorFunc {
 // we will create a less safer functions to get performance
 func (f *Flow) makeExecutor(id string, fn interface{}) executorFunc {
 	return func(ctx OpCtx, params ...Data) (Data, error) {
-		var err error
-
-		//panic recoverer, since nodes are not our functions
-		defer func() {
-			if r := recover(); r != nil {
-				err = fmt.Errorf("%v", r)
-			}
-		}()
 
 		op := f.GetOp(id)
 		if op == nil {
@@ -97,13 +104,13 @@ func (f *Flow) makeExecutor(id string, fn interface{}) executorFunc {
 				return v, nil
 			}
 		}
-
 		// Change to wait
 		f.hooks.wait(id)
 
 		fnval := reflect.ValueOf(fn)
 		callParam, err := f.processInputs(ctx, op, fnval, params...)
 		if err != nil {
+			log.Println("ERR", err)
 			return nil, err
 		}
 
@@ -165,9 +172,9 @@ func (f *Flow) processInputs(ctx OpCtx, op *operation, fnval reflect.Value, para
 				return
 			}
 			if fr == nil {
-				callParam[i] = reflect.ValueOf(reflect.Zero(inTyp).Interface())
+				callParam[i] = reflect.Zero(inTyp)
+				return
 			}
-
 			res := reflect.ValueOf(fr)
 			var cres reflect.Value
 
@@ -179,6 +186,7 @@ func (f *Flow) processInputs(ctx OpCtx, op *operation, fnval reflect.Value, para
 			case !res.Type().ConvertibleTo(inTyp):
 				if inTyp.Kind() != reflect.String {
 					callErrors += fmt.Sprintf("Input %d type: %v(%v) cannot be converted to %v\n", i, res.Type(), res.Interface(), inTyp)
+					log.Println(f)
 					return
 				}
 				cres = reflect.ValueOf(fmt.Sprint(res.Interface()))
@@ -304,14 +312,19 @@ func (f *Flow) DefConst(id string, value Data) (Operation, error) {
 // DefIn define input operation
 func (f *Flow) DefIn(id string, paramID int) Operation {
 	op := &operation{
-		id:       id,
-		Mutex:    sync.Mutex{},
-		flow:     f,
-		name:     fmt.Sprintf("(in)<%d>", paramID),
-		kind:     "in",
-		inputs:   nil,
-		setter:   nil,
-		executor: f.asTrigger(id, func(ctx OpCtx, params ...Data) (Data, error) { return params[paramID], nil }),
+		id:     id,
+		Mutex:  sync.Mutex{},
+		flow:   f,
+		name:   fmt.Sprintf("(in)<%d>", paramID),
+		kind:   "in",
+		inputs: nil,
+		setter: nil,
+		executor: f.asTrigger(id, func(ctx OpCtx, params ...Data) (Data, error) {
+			if paramID < 0 || paramID > len(params) {
+				return nil, ErrInput
+			}
+			return params[paramID], nil
+		}),
 	}
 	f.operations.Store(id, op)
 	return op

+ 1 - 0
go/src/flow/registry/entry.go

@@ -18,6 +18,7 @@ type Entry struct {
 	Inputs      []reflect.Type
 	Output      reflect.Type
 	Description *Description
+	Err         error
 }
 
 // NewEntry creates and describes a New Entry

+ 29 - 30
go/src/flow/registry/registry.go

@@ -9,7 +9,6 @@ import (
 // Global
 var (
 	Global       = New()
-	Register     = Global.Register
 	Descriptions = Global.Descriptions
 	GetEntry     = Global.Entry
 	Add          = Global.Add
@@ -40,37 +39,46 @@ func (r *R) Clone() *R {
 }
 
 // Add function to registry
-func (r *R) Add(fns ...interface{}) (EDescriber, error) {
+func (r *R) Add(args ...interface{}) EDescriber {
+
+	var nextName string
+	var name string
+	var fn interface{}
 
 	b := EDescriber{}
-	for _, fn := range fns {
-		if reflect.TypeOf(fn).Kind() != reflect.Func {
-			return nil, ErrNotAFunc
+	for _, a := range args {
+		switch f := a.(type) {
+		case string:
+			nextName = f
+			continue
+		default:
+			fn = a
+			if reflect.TypeOf(fn).Kind() != reflect.Func {
+				panic(ErrNotAFunc)
+			}
+			// consume name
+			if nextName != "" {
+				name = nextName
+				nextName = ""
+			} else {
+				// Automatic naming
+				name = runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
+				name = path.Ext(name)[1:]
+			}
 		}
-		// Automatic naming
-		name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
-		name = path.Ext(name)[1:]
-		e, err := r.Register(name, fn)
+
+		e, err := r.register(name, fn)
 		if err != nil {
-			return nil, err
+			panic(err)
 		}
 		b = append(b, e)
 	}
 
-	return b, nil
-}
-
-// MustAdd adds a function to registry or panics
-func (r *R) MustAdd(fns ...interface{}) EDescriber {
-	d, err := r.Add(fns...)
-	if err != nil {
-		panic(err)
-	}
-	return d
+	return b
 }
 
 //Register should be a func only register
-func (r *R) Register(name string, v interface{}) (*Entry, error) {
+func (r *R) register(name string, v interface{}) (*Entry, error) {
 	e, err := NewEntry(r, v)
 	if err != nil {
 		return nil, err
@@ -79,15 +87,6 @@ func (r *R) Register(name string, v interface{}) (*Entry, error) {
 	return e, nil
 }
 
-// MustRegister register a function or panic on error
-func (r *R) MustRegister(name string, v interface{}) *Entry {
-	e, err := r.Register(name, v)
-	if err != nil {
-		panic(err)
-	}
-	return e
-}
-
 // Get an entry
 func (r *R) Get(name string, params ...interface{}) (interface{}, error) {
 	e, ok := r.data[name]

+ 0 - 5
go/src/flowserver/cmd/buildops/main.go

@@ -1,5 +0,0 @@
-package main
-
-func main() {
-
-}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 5265 - 0
go/src/flowserver/cmd/demo1/assets/assets.go


+ 11 - 11
go/src/flowserver/cmd/demo1/defaultops/defaultops.go

@@ -16,21 +16,21 @@ func New() *registry.R {
 	r := registry.New()
 	// String functions
 	registry.Describer(
-		r.MustAdd(strings.Split).Inputs("string", "separator"),
-		r.MustAdd(strings.Join).Inputs("", "sep"),
-		r.MustAdd(strings.Compare, strings.Contains),
-		r.MustRegister("Cat", func(a, b string) string { return a + " " + b }),
-		r.MustRegister("ToString", func(a interface{}) string { return fmt.Sprint(a) }),
+		r.Add(strings.Split).Inputs("string", "separator"),
+		r.Add(strings.Join).Inputs("", "sep"),
+		r.Add(strings.Compare, strings.Contains),
+		r.Add("Cat", func(a, b string) string { return a + " " + b }),
+		r.Add("ToString", func(a interface{}) string { return fmt.Sprint(a) }),
 	).Tags("string").Extra("style", registry.M{"color": "#839"})
 
 	// Math functions
-	r.MustAdd(
+	r.Add(
 		math.Abs, math.Cos, math.Sin, math.Exp, math.Exp2, math.Tanh, math.Max, math.Min,
 	).Tags("math").Extra("style", registry.M{"color": "#386"})
 
 	registry.Describer(
-		r.MustAdd(rand.Int, rand.Intn, rand.Float64),
-		r.MustRegister("Perm", func(n int) []int {
+		r.Add(rand.Int, rand.Intn, rand.Float64),
+		r.Add("Perm", func(n int) []int {
 			if n > 10 { // Limiter for safety
 				n = 10
 			}
@@ -39,12 +39,12 @@ func New() *registry.R {
 	).Tags("rand").Extra("style", registry.M{"color": "#486"})
 
 	// Test functions
-	r.MustAdd(testErrorPanic, testErrorDelayed, testRandomError).
+	r.Add(testErrorPanic, testErrorDelayed, testRandomError).
 		Tags("testing-errors")
 
 	registry.Describer(
-		r.MustRegister("wait", wait),
-		r.MustRegister("waitRandom", waitRandom),
+		r.Add("wait", wait),
+		r.Add("waitRandom", waitRandom),
 	).Tags("testing-time").Extra("style", map[string]string{"color": "#8a5"})
 	return r
 }

+ 1 - 1
go/src/flowserver/cmd/demo1/devops/devops.go

@@ -14,7 +14,7 @@ func New() *registry.R {
 
 	r := registry.New()
 
-	r.MustAdd(
+	r.Add(
 		dockerNew,
 		setWriter,
 		dockerTest,

+ 2 - 2
go/src/flowserver/cmd/demo1/gonumops/gonumops.go

@@ -20,8 +20,8 @@ func New() *registry.R {
 	r := registry.New()
 
 	registry.Describer(
-		r.MustAdd(tensorNew).Inputs("rows", "columns", "data"),
-		r.MustAdd(myVar,
+		r.Add(tensorNew).Inputs("rows", "columns", "data"),
+		r.Add(
 			normFloat,
 			tensorMul,
 			tensorTranspose,

+ 0 - 2
go/src/flowserver/cmd/demo1/main.go

@@ -6,7 +6,6 @@ import (
 	"flowserver/cmd/demo1/defaultops"
 	"flowserver/cmd/demo1/devops"
 	"flowserver/cmd/demo1/gonumops"
-	"flowserver/cmd/demo1/testops"
 	"log"
 	"mime"
 	"net/http"
@@ -36,7 +35,6 @@ func main() {
 	mux.Handle("/default/", c.Build(flowserver.New(defaultops.New(), "default").ServeHTTP))
 	mux.Handle("/gonumops/", c.Build(flowserver.New(gonumops.New(), "gonumops").ServeHTTP))
 	mux.Handle("/devops/", c.Build(flowserver.New(devops.New(), "devops").ServeHTTP))
-	mux.Handle("/testops/", c.Build(flowserver.New(testops.New(), "tests").ServeHTTP))
 
 	// Context registry
 	http.ListenAndServe(addr, mux)

+ 40 - 0
go/src/flowserver/cmd/demo1/static/c1.html

@@ -0,0 +1,40 @@
+<html>
+<head>
+<style type="text/css">
+pre { font-family: monospace; color: #d0d0d0; background-color: #121212; }
+* { font-size: 1em; }
+.Statement { color: #d7005f; font-weight: bold; }
+.String { color: #afaf87; }
+.Function { color: #87ff00; }
+.Operator { color: #d7005f; }
+.LineNr { color: #bcbcbc; background-color: #303030; padding-bottom: 1px; }
+.Keyword { color: #d7005f; font-weight: bold; }
+.Type { color: #5fd7ff; }
+-->
+</style>
+
+</head>
+<body >
+<pre id='vimCodeElement'>
+<span id="L1" class="LineNr"> 1 </span><span class="Statement">package</span> main
+<span id="L2" class="LineNr"> 2 </span>
+<span id="L3" class="LineNr"> 3 </span><span class="Statement">import</span> (
+<span id="L4" class="LineNr"> 4 </span>  <span class="String">&quot;flow/registry&quot;</span>
+<span id="L5" class="LineNr"> 5 </span>  <span class="String">&quot;flowserver&quot;</span>
+<span id="L6" class="LineNr"> 6 </span>  <span class="String">&quot;net/http&quot;</span>
+<span id="L7" class="LineNr"> 7 </span>)
+<span id="L8" class="LineNr"> 8 </span>
+<span id="L9" class="LineNr"> 9 </span><span class="Keyword">func</span> <span class="Function">main</span>() {
+<span id="L10" class="LineNr">10 </span>
+<span id="L11" class="LineNr">11 </span>  r <span class="Operator">:=</span> registry.New()
+<span id="L12" class="LineNr">12 </span>  r.Register(<span class="String">&quot;hello&quot;</span>, <span class="Keyword">func</span>() <span class="Type">string</span> {
+<span id="L13" class="LineNr">13 </span>    <span class="Statement">return</span> <span class="String">&quot;hello world&quot;</span>
+<span id="L14" class="LineNr">14 </span>  })
+<span id="L15" class="LineNr">15 </span>
+<span id="L16" class="LineNr">16 </span>  http.ListenAndServe(<span class="String">&quot;:5000&quot;</span>, flowserver.New(r, <span class="String">&quot;storename&quot;</span>))
+<span id="L17" class="LineNr">17 </span>
+<span id="L18" class="LineNr">18 </span>}
+</pre>
+</body>
+</html>
+<!-- vim: set foldmethod=manual : -->

+ 45 - 0
go/src/flowserver/cmd/demo1/static/c2.html

@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<style type="text/css">
+pre { font-family: monospace; color: #d0d0d0; background-color: #121212; }
+* { font-size: 1em; }
+.Statement { color: #d7005f; font-weight: bold; }
+.String { color: #afaf87; }
+.Function { color: #87ff00; }
+.Operator { color: #d7005f; }
+.LineNr { color: #bcbcbc; background-color: #303030; padding-bottom: 1px; }
+.Keyword { color: #d7005f; font-weight: bold; }
+.Type { color: #5fd7ff; }
+</style>
+</head>
+<body>
+
+<pre id='vimCodeElement'>
+<span id="L1" class="LineNr"> 1 </span><span class="Statement">package</span> main
+<span id="L2" class="LineNr"> 2 </span>
+<span id="L3" class="LineNr"> 3 </span><span class="Statement">import</span> (
+<span id="L4" class="LineNr"> 4 </span>  <span class="String">&quot;flow/registry&quot;</span>
+<span id="L5" class="LineNr"> 5 </span>  <span class="String">&quot;flowserver&quot;</span>
+<span id="L6" class="LineNr"> 6 </span>  <span class="String">&quot;net/http&quot;</span>
+<span id="L7" class="LineNr"> 7 </span>  <span class="String">&quot;strings&quot;</span>
+<span id="L8" class="LineNr"> 8 </span>)
+<span id="L9" class="LineNr"> 9 </span>
+<span id="L10" class="LineNr">10 </span><span class="Keyword">func</span> <span class="Function">main</span>() {
+<span id="L11" class="LineNr">11 </span>
+<span id="L12" class="LineNr">12 </span>  r <span class="Operator">:=</span> registry.New()
+<span id="L13" class="LineNr">13 </span>  r.Register(<span class="String">&quot;hello&quot;</span>, <span class="Keyword">func</span>() <span class="Type">string</span> {
+<span id="L14" class="LineNr">14 </span>    <span class="Statement">return</span> <span class="String">&quot;hello world&quot;</span>
+<span id="L15" class="LineNr">15 </span>  })
+<span id="L16" class="LineNr">16 </span>  r.Add(strings.Split, strings.Join)
+<span id="L17" class="LineNr">17 </span>
+<span id="L18" class="LineNr">18 </span>  http.ListenAndServe(<span class="String">&quot;:5000&quot;</span>, flowserver.New(r, <span class="String">&quot;storename&quot;</span>))
+<span id="L19" class="LineNr">19 </span>
+<span id="L20" class="LineNr">20 </span>}
+</pre>
+<img src="c2.jpg">
+
+</body>
+</html>
+
+<!-- vim: set foldmethod=manual : -->

BIN
go/src/flowserver/cmd/demo1/static/c2.jpg


+ 67 - 0
go/src/flowserver/cmd/demo1/static/c3.html

@@ -0,0 +1,67 @@
+<html>
+<head>
+<style type="text/css">
+<!--
+pre { font-family: monospace; color: #d0d0d0; background-color: #121212; }
+* { font-size: 1em; }
+.Statement { color: #d7005f; font-weight: bold; }
+.String { color: #afaf87; }
+.Conditional { color: #d7005f; font-weight: bold; }
+.Function { color: #87ff00; }
+.Boolean { color: #af5fff; }
+.Operator { color: #d7005f; }
+.LineNr { color: #bcbcbc; background-color: #303030; padding-bottom: 1px; }
+.Keyword { color: #d7005f; font-weight: bold; }
+.Comment { color: #5f5f5f; }
+.Type { color: #5fd7ff; }
+-->
+</style>
+</head>
+<pre id='vimCodeElement'>
+<span id="L1" class="LineNr"> 1 </span><span class="Statement">package</span> main
+<span id="L2" class="LineNr"> 2 </span>
+<span id="L3" class="LineNr"> 3 </span><span class="Statement">import</span> (
+<span id="L4" class="LineNr"> 4 </span>  <span class="String">&quot;flow/registry&quot;</span>
+<span id="L5" class="LineNr"> 5 </span>  <span class="String">&quot;flowserver&quot;</span>
+<span id="L6" class="LineNr"> 6 </span>  <span class="String">&quot;io/ioutil&quot;</span>
+<span id="L7" class="LineNr"> 7 </span>  <span class="String">&quot;log&quot;</span>
+<span id="L8" class="LineNr"> 8 </span>  <span class="String">&quot;math&quot;</span>
+<span id="L9" class="LineNr"> 9 </span>  <span class="String">&quot;net/http&quot;</span>
+<span id="L10" class="LineNr">10 </span>  <span class="String">&quot;strings&quot;</span>
+<span id="L11" class="LineNr">11 </span>)
+<span id="L12" class="LineNr">12 </span>
+<span id="L13" class="LineNr">13 </span><span class="Keyword">func</span> <span class="Function">main</span>() {
+<span id="L14" class="LineNr">14 </span>
+<span id="L15" class="LineNr">15 </span>  r <span class="Operator">:=</span> registry.New()
+<span id="L16" class="LineNr">16 </span>  r.Register(<span class="String">&quot;hello&quot;</span>, <span class="Keyword">func</span>() <span class="Type">string</span> {
+<span id="L17" class="LineNr">17 </span>    <span class="Statement">return</span> <span class="String">&quot;hello world&quot;</span>
+<span id="L18" class="LineNr">18 </span>  })
+<span id="L19" class="LineNr">19 </span>  r.Add(strings.Split, strings.Join)
+<span id="L20" class="LineNr">20 </span>
+<span id="L21" class="LineNr">21 </span>  fns, err <span class="Operator">:=</span> r.Add(math.Exp, math.Sin, math.Cos)
+<span id="L22" class="LineNr">22 </span>  <span class="Conditional">if</span> err <span class="Operator">!=</span> <span class="Boolean">nil</span> {
+<span id="L23" class="LineNr">23 </span>    log.Fatal(err)
+<span id="L24" class="LineNr">24 </span>  }
+<span id="L25" class="LineNr">25 </span><span class="Comment">  //Describing groups of functions</span>
+<span id="L26" class="LineNr">26 </span>  fns.Tags(<span class="String">&quot;math&quot;</span>)
+<span id="L27" class="LineNr">27 </span>  fns.Extra(<span class="String">&quot;style&quot;</span>, registry.M{<span class="String">&quot;color&quot;</span>: <span class="String">&quot;#F00&quot;</span>})
+<span id="L28" class="LineNr">28 </span>
+<span id="L29" class="LineNr">29 </span><span class="Comment">  // Describing a function</span>
+<span id="L30" class="LineNr">30 </span>  registry.Describer(
+<span id="L31" class="LineNr">31 </span>    r.MustAdd(http.Get).Inputs(<span class="String">&quot;url&quot;</span>),
+<span id="L32" class="LineNr">32 </span>    r.MustAdd(responseReader).Inputs(<span class="String">&quot;response&quot;</span>),
+<span id="L33" class="LineNr">33 </span>  ).Tags(<span class="String">&quot;http&quot;</span>).Extra(<span class="String">&quot;style&quot;</span>, registry.M{<span class="String">&quot;color&quot;</span>: <span class="String">&quot;#00F&quot;</span>})
+<span id="L34" class="LineNr">34 </span>
+<span id="L35" class="LineNr">35 </span>  http.ListenAndServe(<span class="String">&quot;:5000&quot;</span>, flowserver.New(r, <span class="String">&quot;storename&quot;</span>))
+<span id="L36" class="LineNr">36 </span>
+<span id="L37" class="LineNr">37 </span>}
+<span id="L38" class="LineNr">38 </span><span class="Keyword">func</span> <span class="Function">responseReader</span>(r <span class="Operator">*</span>http.Response) (<span class="Type">string</span>, <span class="Type">error</span>) {
+<span id="L39" class="LineNr">39 </span>  <span class="Statement">defer</span> r.Body.Close()
+<span id="L40" class="LineNr">40 </span>  res, err <span class="Operator">:=</span> ioutil.ReadAll(r.Body)
+<span id="L41" class="LineNr">41 </span>  <span class="Statement">return</span> <span class="Type">string</span>(res), err
+<span id="L42" class="LineNr">42 </span>}
+</pre>
+<img src="c3.jpg">
+</body>
+</html
+

BIN
go/src/flowserver/cmd/demo1/static/c3.jpg


+ 0 - 19
go/src/flowserver/cmd/demo1/testops/testops.go

@@ -1,19 +0,0 @@
-package testops
-
-import "flow/registry"
-
-func New() *registry.R {
-
-	r := registry.New()
-
-	r.Register("myfunc", testLabels)
-
-	return r
-}
-
-type Bignamedtypetotestthelabelsinthesockets int
-
-func testLabels(a Bignamedtypetotestthelabelsinthesockets, b int) Bignamedtypetotestthelabelsinthesockets {
-	return Bignamedtypetotestthelabelsinthesockets(1)
-
-}

+ 38 - 0
go/src/flowserver/cmd/simple/main.go

@@ -0,0 +1,38 @@
+package main
+
+import (
+	"flow/registry"
+	"flowserver"
+	"io/ioutil"
+	"math"
+	"net/http"
+	"strings"
+)
+
+func main() {
+
+	r := registry.New()
+	r.Add("hello", func() string {
+		return "hello world"
+	})
+	r.Add(strings.Split, strings.Join)
+
+	fns := r.Add(math.Exp, math.Sin, math.Cos)
+	//Describing groups of functions
+	fns.Tags("math")
+	fns.Extra("style", registry.M{"color": "#F00"})
+
+	// Describing a function
+	registry.Describer(
+		r.Add(http.Get).Inputs("url"),
+		r.Add(responseReader).Inputs("response"),
+	).Tags("http").Extra("style", registry.M{"color": "#00F"})
+
+	http.ListenAndServe(":5000", flowserver.New(r, "storename"))
+
+}
+func responseReader(r *http.Response) (string, error) {
+	defer r.Body.Close()
+	res, err := ioutil.ReadAll(r.Body)
+	return string(res), err
+}

+ 13 - 9
go/src/flowserver/flowbuilder/builder.go

@@ -182,6 +182,10 @@ func (fb *FlowBuilder) Flow() *flow.Flow {
 
 // Or give a string
 func parseValue(typ reflect.Type, raw string) (flow.Data, error) {
+
+	if len(raw) == 0 {
+		return nil, nil
+	}
 	if typ == nil {
 		var val flow.Data
 		err := json.Unmarshal([]byte(raw), &val)
@@ -196,7 +200,6 @@ func parseValue(typ reflect.Type, raw string) (flow.Data, error) {
 	case reflect.Int:
 		v, err := strconv.Atoi(raw)
 		if err != nil {
-			log.Println("Wrong int conversion", err)
 			return nil, err
 		}
 		ret = v
@@ -204,15 +207,16 @@ func parseValue(typ reflect.Type, raw string) (flow.Data, error) {
 		ret = raw
 	default:
 		if len(raw) == 0 {
-			ret = reflect.Zero(typ)
-		} else {
-			refVal := reflect.New(typ)
-			err := json.Unmarshal([]byte(raw), refVal.Interface())
-			if err != nil {
-				return nil, err
-			}
-			ret = refVal.Elem().Interface()
+			return nil, nil
+		}
+		//ret = reflect.Zero(typ)
+
+		refVal := reflect.New(typ)
+		err := json.Unmarshal([]byte(raw), refVal.Interface())
+		if err != nil {
+			return nil, err
 		}
+		ret = refVal.Elem().Interface()
 	}
 	return ret, nil
 }

+ 9 - 4
go/src/flowserver/session.go

@@ -189,22 +189,23 @@ func (s *FlowSession) NodeRun(c *websocket.Conn, data []byte) error {
 
 		localR := s.manager.registry.Clone()
 		//Add our log func that is not in global registry
-		localR.Register("Notify", func(v flow.Data, msg string) flow.Data {
+		localR.Add("Notify", func(v flow.Data, msg string) flow.Data {
+			log.Println("Notify:", msg)
 			s.Notify(msg)
 			return v
 		})
-		localR.Register("Log", func() io.Writer {
+		localR.Add("Log", func() io.Writer {
 			return s
 		})
 		// Special func
-		localR.Register("Variable", func(name string, initial flow.Data) flow.Data {
+		localR.Add("Variable", func(name string, initial flow.Data) flow.Data {
 			_, ok := s.flow.Data[name]
 			if !ok {
 				s.flow.Data[name] = initial
 			}
 			return s.flow.Data[name]
 		})
-		localR.Register("Output", func(d interface{}) {
+		localR.Add("Output", func(d interface{}) {
 
 			r := fmt.Sprint("Result:", d)
 			// Do something
@@ -217,6 +218,7 @@ func (s *FlowSession) NodeRun(c *websocket.Conn, data []byte) error {
 		if builder.Err != nil {
 			return builder.Err
 		}
+		log.Println("New flow")
 		s.flow = builder.Flow()
 
 		defer func() { // After routing gone
@@ -264,10 +266,13 @@ func (s *FlowSession) NodeRun(c *websocket.Conn, data []byte) error {
 		if op == nil {
 			return fmt.Errorf("Operation not found %v", ID)
 		}
+		log.Println("Processing operation")
 		_, err := op.Process()
 		if err != nil {
+			log.Println("Error operation", err)
 			return err
 		}
+		log.Println("Operation finish")
 		return nil
 	}