mirror of
https://github.com/dragonheim/gagent.git
synced 2025-02-23 10:29:54 -08:00
commit
aa0e396e35
6 changed files with 132 additions and 48 deletions
|
@ -5,12 +5,10 @@ name: default
|
|||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm
|
||||
arch: amd64
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
include:
|
||||
- issues/1
|
||||
exclude:
|
||||
- main
|
||||
|
||||
|
|
32
README.md
32
README.md
|
@ -1,9 +1,39 @@
|
|||
# G'Agent
|
||||
[](https://drone.dragonheim.net/dragonheim/gagent)
|
||||
|
||||
|
||||
A mobile agent system, written in Go, loosely inspired by the [Agent Tcl / D'Agents](http://www.cs.dartmouth.edu/~dfk/agents/) system created by Robert S. Gray of Dartmouth college.
|
||||
|
||||
## Purpose
|
||||
As we move close and closer to a true space age, we need to start thinking about solutions for various light-speed issues such as the bi-directional time delay between the surface of Mars and the surface of Earth. At present it takes between 6 minutes and 44 minutes for single round-trip, making most current data services unuseable. G'Agent is a potential solution for data services given the time delay.
|
||||
|
||||
Imagine, for a moment, that you are on Mars and need to perform a search for data in a specific domain space. You would have to explain it to someone on Earth, and hope they understand enough of the data / domain to know where to search and understand you well enough to perform the actual search and then send you the results. With G'Agent, instead you would write a basic script, hereafter called an agent, providing various hints as to the domain space as well as the actual search. Your client would then send it on to a server on Earth. The server, hereafter called a router, may or nothing about the domain space of your search, so the router will use the hints that you provide to attempt to route the request to other routers that may understand the specific domain space. Eventually your agent will reach a router whose servers, hereafter referred to as workers, can handle your search. The workers, will take the agent, run the script portion and collect the response(s). The worker will send the response back to the router(s) that it recieved the agent from, eventually routing it back to you.
|
||||
|
||||
## Example Agent
|
||||
```tcl
|
||||
1 : ###################
|
||||
2 : ### Hello Earth ###
|
||||
3 : ###################
|
||||
4 : # HINT START
|
||||
5 : # - console
|
||||
6 : # - gravity measurements
|
||||
7 : # - gravity fluctuations
|
||||
8 : # HINT END
|
||||
9 : function hello_world() {
|
||||
10: console.log("Hello Earth, does tempurature various alter specific gravity?")
|
||||
11: }
|
||||
12: console.log(hello_world())
|
||||
```
|
||||
Lines 1 - 3 are simple comments
|
||||
|
||||
Line 4 Tells the G'Agent router that this is the start of the hints to route for.
|
||||
|
||||
Lines 5 - 7 are a list of hints that the router will use to determine which router(s) may have domain specific information.
|
||||
|
||||
Lines 9 - 11 are a tcl function that will be executed on the worker before sending the results back to the client.
|
||||
|
||||
Line 12 executes the function defined above.
|
||||
|
||||
## History
|
||||
More information can be found in the original [documentation](http://www.cs.dartmouth.edu/~dfk/agents/pub/agents/doc.5.1.ps.gz), and in the project's [wiki](https://git.dragonheim.net/dragonheim/gagent/wiki/_pages).
|
||||
|
||||
We are adding Picol as a vendor package though we have modified it specific to support a subset of the [Agent Tcl / D'Agents](http://www.cs.dartmouth.edu/~dfk/agents/pub/agents/doc.5.1.ps.gz) language extensions. The language extensions can be found in the [LANGUAGE.md](https://git.dragonheim.net/dragonheim/gagent/src/branch/main/LANGUAGE.md) file.
|
||||
|
|
|
@ -24,6 +24,34 @@ name = "gagent-zulu.example.org"
|
|||
*/
|
||||
mode = "router"
|
||||
|
||||
/*
|
||||
* This is the UUID used throughout the G'Agent system
|
||||
* to uniquely identify this node. It is generated
|
||||
* during setup.
|
||||
*
|
||||
* Required.
|
||||
*/
|
||||
uuid = "7e9d13fe-5151-5876-66c0-20ca03e8fca4"
|
||||
|
||||
/*
|
||||
* This is the IP Address to bind to, it defaults to
|
||||
* 0.0.0.0
|
||||
*
|
||||
* Optional.
|
||||
*
|
||||
* listenaddr = 0.0.0.0
|
||||
*/
|
||||
|
||||
/.
|
||||
* This is the port to listen on, it defaults to
|
||||
* 33570. It is strongly recommended that you not
|
||||
* use ports 0 - 1024
|
||||
*
|
||||
* Optional.
|
||||
*
|
||||
* listenport = 33570
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the UUID used throughout the G'Agent system
|
||||
* to uniquely identify this node.
|
||||
|
@ -32,6 +60,23 @@ mode = "router"
|
|||
*/
|
||||
// uuid = "04f97538-270d-4ca3-b782-e09ef35830e9"
|
||||
|
||||
/*
|
||||
* This is the list of known G'Agent clients. Clients
|
||||
* are not registered dynamically, instead the only
|
||||
* clients that may connect are those listed here,
|
||||
* but client's of other routers may route, via tags,
|
||||
* their agent here.
|
||||
*
|
||||
* Optional.
|
||||
*/
|
||||
// client "alpha" {
|
||||
// uuid = "04f97538-270d-4ce3-b782-e09ef35830e9"
|
||||
// }
|
||||
//
|
||||
// client "beta" {
|
||||
// uuid = "04f97538-270d-4cf3-b782-e09ef35830e9"
|
||||
// }
|
||||
|
||||
/*
|
||||
* This is a list of known G'Agent routers. At least
|
||||
* one router is required for workers and clients. If
|
||||
|
@ -39,19 +84,19 @@ mode = "router"
|
|||
* will connect to them in sequential order.
|
||||
*/
|
||||
// router "alpha" {
|
||||
// routerid = "04f97538-270d-4cb3-b782-e09ef35830e9"
|
||||
// uuid = "04f97538-270d-4cb3-b782-e09ef35830e9"
|
||||
// address = "gagent-alpha.example.org"
|
||||
// tags = [ "a", "b", "c", "d" ]
|
||||
// }
|
||||
//
|
||||
// router "beta" {
|
||||
// routerid = "04f97538-270d-4cc3-b782-e09ef35830e9"
|
||||
// uuid = "04f97538-270d-4cc3-b782-e09ef35830e9"
|
||||
// address = "gagent-beta.example.org"
|
||||
// tags = [ "a", "c", "e", "g" ]
|
||||
// }
|
||||
//
|
||||
// router "charlie" {
|
||||
// routerid = "04f97538-270d-4cd3-b782-e09ef35830e9"
|
||||
// uuid = "04f97538-270d-4cd3-b782-e09ef35830e9"
|
||||
// address = "gagent-charlie.example.org"
|
||||
// tags = [ "b", "d", "f", "h" ]
|
||||
// }
|
||||
|
@ -64,20 +109,18 @@ mode = "router"
|
|||
* At least one worker is reuqired for routers.
|
||||
*/
|
||||
// worker "alpha" {
|
||||
// workerid = "04f97538-270d-4ce3-b782-e09ef35830e9"
|
||||
// uuid = "04f97538-270d-4ce3-b782-e09ef35830e9"
|
||||
// address = "gagent-alpha.example.org"
|
||||
// tags = [ "a", "b", "c", "d" ]
|
||||
// }
|
||||
//
|
||||
// worker "beta" {
|
||||
// workerid = "04f97538-270d-4cf3-b782-e09ef35830e9"
|
||||
// address = "gagent-beta.example.org"
|
||||
// uuid = "04f97538-270d-4cf3-b782-e09ef35830e9"
|
||||
// tags = [ "a", "c", "e", "g" ]
|
||||
// }
|
||||
//
|
||||
// worker "charlie" {
|
||||
// workerid = "04f97538-270d-4c04-b782-e09ef35830e9"
|
||||
// address = "gagent-charlie.example.org"
|
||||
// uuid = "04f97538-270d-4c04-b782-e09ef35830e9"
|
||||
// tags = [ "b", "d", "f", "h" ]
|
||||
// }
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
// client "git.dragonheim.net/dragonheim/gagent/src/client"
|
||||
gr "git.dragonheim.net/dragonheim/gagent/src/router"
|
||||
// worker "git.dragonheim.net/dragonheim/gagent/src/worker"
|
||||
gw "git.dragonheim.net/dragonheim/gagent/src/worker"
|
||||
|
||||
docopt "github.com/aviddiviner/docopt-go"
|
||||
hclsimple "github.com/hashicorp/hcl/v2/hclsimple"
|
||||
|
@ -30,7 +30,6 @@ var exitCodes = struct {
|
|||
"AGENT_LOAD_FAILED": 4,
|
||||
"AGENT_MISSING_TAGS": 5,
|
||||
"NO_ROUTERS_DEFINED": 6,
|
||||
"NO_WORKERS_DEFINED": 6,
|
||||
"NO_WORKERS_DEFINED": 7,
|
||||
}}
|
||||
|
||||
|
@ -149,6 +148,12 @@ func main() {
|
|||
log.Printf("Arguments are %v\n", arguments)
|
||||
log.Printf("Configuration is %v\n", config)
|
||||
log.Printf("Running in router mode\n")
|
||||
|
||||
if len(config.Workers) == 0 {
|
||||
log.Printf("No workers defined.\n")
|
||||
os.Exit(exitCodes.m["NO_WORKERS_DEFINED"])
|
||||
}
|
||||
|
||||
go gr.Main(config)
|
||||
select {}
|
||||
|
||||
|
@ -161,8 +166,15 @@ func main() {
|
|||
*/
|
||||
log.Printf("Arguments are %v\n", arguments)
|
||||
log.Printf("Configuration is %v\n", config)
|
||||
// go worker.Main(config)
|
||||
// select {}
|
||||
log.Printf("Running in worker mode\n")
|
||||
|
||||
if len(config.Routers) == 0 {
|
||||
log.Printf("No routers defined.\n")
|
||||
os.Exit(exitCodes.m["NO_ROUTERS_DEFINED"])
|
||||
}
|
||||
|
||||
go gw.Main(config)
|
||||
select {}
|
||||
|
||||
case "setup":
|
||||
log.Printf("Running in setup mode\n")
|
||||
|
|
|
@ -5,8 +5,8 @@ type GagentConfig struct {
|
|||
Name string `hcl:"name,optional"`
|
||||
Mode string `hcl:"mode,attr"`
|
||||
UUID string `hcl:"uuid,optional"`
|
||||
ListenAddr string `hcl:"address,optional"`
|
||||
ListenPort int `hcl:"port,optional"`
|
||||
ListenAddr string `hcl:"listenaddr,optional"`
|
||||
ListenPort int `hcl:"listenport,optional"`
|
||||
Clients []*ClientDetails `hcl:"client,block"`
|
||||
Routers []*RouterDetails `hcl:"router,block"`
|
||||
Workers []*WorkerDetails `hcl:"worker,block"`
|
||||
|
@ -43,7 +43,7 @@ type RouterDetails struct {
|
|||
* which MQ router to send the agent's requests to.
|
||||
* This attempts to keep the routers unique globally.
|
||||
*/
|
||||
RouterID string `hcl:"routerid,attr"`
|
||||
RouterID string `hcl:"uuid,attr"`
|
||||
|
||||
/*
|
||||
* This is the IP Address and port that the router
|
||||
|
@ -75,7 +75,7 @@ type WorkerDetails struct {
|
|||
* send agents to. This attempts to keep the
|
||||
* workers unique globally.
|
||||
*/
|
||||
WorkerID string `hcl:"workerid,attr"`
|
||||
WorkerID string `hcl:"uuid,attr"`
|
||||
|
||||
/*
|
||||
* These tags will be passed to the router upon
|
||||
|
|
|
@ -2,7 +2,7 @@ package worker
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
// "log"
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
|
@ -23,34 +23,8 @@ func pop(msg []string) (head, tail []string) {
|
|||
return
|
||||
}
|
||||
|
||||
// Main is the initiation function for a Worker
|
||||
func Main(config gs.GagentConfig) {
|
||||
// Frontend socket talks to clients over TCP
|
||||
frontend, _ := zmq.NewSocket(zmq.ROUTER)
|
||||
fmt.Printf("Running in worker mode\n")
|
||||
|
||||
defer frontend.Close()
|
||||
connectString := fmt.Sprintf("tcp://%s", config.Routers[0].RouterAddr)
|
||||
frontend.Bind(connectString)
|
||||
|
||||
// Backend socket talks to workers over inproc
|
||||
backend, _ := zmq.NewSocket(zmq.DEALER)
|
||||
defer backend.Close()
|
||||
backend.Bind("inproc://backend")
|
||||
|
||||
// Launch pool of agent handlers
|
||||
for i := 0; i < 5; i++ {
|
||||
go agentHandler(i)
|
||||
}
|
||||
|
||||
// Connect backend to frontend via a proxy
|
||||
// err := zmq.Proxy(frontend, backend, nil)
|
||||
// log.Fatalln("Proxy interrupted:", err)
|
||||
}
|
||||
|
||||
// Each worker task works on one request at a time and sends a random number
|
||||
// of replies back, with random delays between replies:
|
||||
|
||||
func agentHandler(workerNum int) {
|
||||
interp := picol.InitInterp()
|
||||
interp.RegisterCoreCommands()
|
||||
|
@ -70,8 +44,35 @@ func agentHandler(workerNum int) {
|
|||
// Sleep for some fraction of a second
|
||||
time.Sleep(time.Duration(rand.Intn(1000)+1) * time.Millisecond)
|
||||
|
||||
fmt.Println(fmt.Sprintf("Worker %d: %s", workerNum, identity))
|
||||
log.Printf(fmt.Sprintf("Worker %d: %s\n", workerNum, identity))
|
||||
worker.SendMessage(identity, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main is the initiation function for a Worker
|
||||
func Main(config gs.GagentConfig) {
|
||||
// Frontend socket talks to clients over TCP
|
||||
frontend, _ := zmq.NewSocket(zmq.ROUTER)
|
||||
log.Printf("Starting worker\n")
|
||||
|
||||
defer frontend.Close()
|
||||
log.Printf("Attempting to connect to: %s(%s)\n", config.Routers[0].RouterName, config.Routers[0].RouterAddr)
|
||||
connectString := fmt.Sprintf("tcp://%s", config.Routers[0].RouterAddr)
|
||||
frontend.Bind(connectString)
|
||||
|
||||
// Backend socket talks to workers over inproc
|
||||
backend, _ := zmq.NewSocket(zmq.DEALER)
|
||||
defer backend.Close()
|
||||
backend.Bind("inproc://backend")
|
||||
|
||||
// Launch pool of agent handlers
|
||||
for i := 0; i < 5; i++ {
|
||||
go agentHandler(i)
|
||||
}
|
||||
|
||||
// Connect backend to frontend via a proxy
|
||||
// err := zmq.Proxy(frontend, backend, nil)
|
||||
// log.Fatalln("Proxy interrupted:", err)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue