Skip to content

Commit

Permalink
Custom handshake/proro/resolver (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
halturin authored Dec 6, 2021
1 parent 61292dc commit c6a30bc
Show file tree
Hide file tree
Showing 66 changed files with 6,103 additions and 4,392 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<h1><a href="https://ergo.services"><img src=".github/images/logo.svg" alt="Ergo Framework" width="159" height="49"></a></h1>

[![GitHub release](https://img.shields.io/github/release/ergo-services/ergo.svg)](https://github.com/ergo-services/ergo/releases/latest)
[![Go Report Card](https://goreportcard.com/badge/github.com/ergo-services/ergo)](https://goreportcard.com/report/github.com/ergo-services/ergo)
[![Gitbook Documentation](https://img.shields.io/badge/GitBook-Documentation-f37f40?style=plastic&logo=gitbook&logoColor=white&style=flat)](https://docs.ergo.services)
[![GoDoc](https://pkg.go.dev/badge/ergo-services/ergo)](https://pkg.go.dev/github.com/ergo-services/ergo)
[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
[![Build Status](https://img.shields.io/github/workflow/status/ergo-services/ergo/TestLinuxWindowsMacOS)](https://github.com/ergo-services/ergo/actions/)
[![Go Report Card](https://goreportcard.com/badge/github.com/ergo-services/ergo)](https://goreportcard.com/report/github.com/ergo-services/ergo)
[![Slack Community](https://img.shields.io/badge/Slack-Community-3f0e40?style=flat&logo=slack)](https://ergoservices.slack.com)

Technologies and design patterns of Erlang/OTP have been proven over the years. Now in Golang.
Up to x5 times faster than original Erlang/OTP in terms of network messaging.
Expand Down Expand Up @@ -59,13 +61,13 @@ The goal of this project is to leverage Erlang/OTP experience with Golang perfor

### Versioning ###

Golang introduced [v2 rule](https://go.dev/blog/v2-go-modules) a while ago to solve complicated dependency issues. We found this solution very controversial and there is still a lot of discussion around it. So, we decided to keep the old way for the versioning, but have to use the git tag versioning with v1 as a major version (due to "v2 rule" restrictions) . As a starting point for the v2.0.0 we use git tag v1.999.200. Since now, the only "patch version" will be increased for the next releases (e.g. v2.0.1 will be tagged in git as v.1.999.201 and so on, but never be above git tag v1.999 until the moment when Golang developers change the versioning approach)
Golang introduced [v2 rule](https://go.dev/blog/v2-go-modules) a while ago to solve complicated dependency issues. We found this solution very controversial and there is still a lot of discussion around it. So, we decided to keep the old way for the versioning, but have to use the git tag with v1 as a major version (due to "v2 rule" restrictions) . As a starting point for the v2.0.0 we use git tag v1.999.200. Since now, the only "patch version" will be increased for the next releases (e.g. v2.0.1 will be tagged in git as v.1.999.201 and so on, but never be above git tag v1.999 until the moment when Golang developers change the versioning approach)

### Changelog ###

Here are the changes of latest release. For more details see the [ChangeLog](ChangeLog.md)

#### [v2.0.0](https://github.com/ergo-services/ergo/releases/tag/v1.999.200) tag version v1.999.200 - 2021-10-12 ####
#### [v2.0.0](https://github.com/ergo-services/ergo/releases/tag/v1.999.200) 2021-10-12 [tag version v1.999.200] ####

* Added support of Erlang/OTP 24 (including [Alias](https://blog.erlang.org/My-OTP-24-Highlights/#eep-53-process-aliases) feature and [Remote Spawn](https://blog.erlang.org/OTP-23-Highlights/#distributed-spawn-and-the-new-erpc-module) introduced in Erlang/OTP 23)
* **Important**: This release includes refined API (without backward compatibility) for a more convenient way to create OTP-designed microservices. Make sure to update your code.
Expand Down
89 changes: 89 additions & 0 deletions cloud/cloudapp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cloud

import (
"github.com/ergo-services/ergo/etf"
"github.com/ergo-services/ergo/gen"
"github.com/ergo-services/ergo/lib"
"github.com/ergo-services/ergo/node"
)

type CloudApp struct {
gen.Application
options node.Cloud
}

func CreateApp(options node.Cloud) gen.ApplicationBehavior {
return &CloudApp{
options: options,
}
}

func (ca *CloudApp) Load(args ...etf.Term) (gen.ApplicationSpec, error) {
return gen.ApplicationSpec{
Name: "cloud_app",
Description: "Ergo Cloud Support Application",
Version: "v.1.0",
Children: []gen.ApplicationChildSpec{
gen.ApplicationChildSpec{
Child: &cloudAppSup{},
Name: "cloud_app_sup",
},
},
}, nil
}

func (ca *CloudApp) Start(p gen.Process, args ...etf.Term) {
// add static route with custom handshake
// cloudHandshake = CreateCloudHandshake()
// node.AddStaticRoute("cloud.ergo.services", node.StaticRouteOptions)
}

type cloudAppSup struct {
gen.Supervisor
}

func (cas *cloudAppSup) Init(args ...etf.Term) (gen.SupervisorSpec, error) {
return gen.SupervisorSpec{
Children: []gen.SupervisorChildSpec{
gen.SupervisorChildSpec{
Name: "cloud_client",
Child: &cloudClient{},
},
},
Strategy: gen.SupervisorStrategy{
Type: gen.SupervisorStrategyOneForOne,
Intensity: 10,
Period: 5,
Restart: gen.SupervisorStrategyRestartPermanent,
},
}, nil
}

type cloudClient struct {
gen.Server
}

func (cc *cloudClient) Init(process *gen.ServerProcess, args ...etf.Term) error {
lib.Log("CLOUD_CLIENT: Init: %#v", args)
// initiate connection with the cloud
return nil
}

func (cc *cloudClient) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
lib.Log("CLOUD_CLIENT: HandleCall: %#v, From: %#v", message, from)
return nil, gen.ServerStatusOK
}

func (cc *cloudClient) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
lib.Log("CLOUD_CLIENT: HandleCast: %#v", message)
return gen.ServerStatusOK
}

func (cc *cloudClient) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
lib.Log("CLOUD_CLIENT: HandleInfo: %#v", message)
return gen.ServerStatusOK
}
func (cc *cloudClient) Terminate(process *gen.ServerProcess, reason string) {
lib.Log("CLOUD_CLIENT: Terminated with reason: %v", reason)
return
}
18 changes: 18 additions & 0 deletions cloud/handshake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cloud

import (
"net"

"github.com/ergo-services/ergo/node"
)

type CloudHandshake struct {
node.Handshake
}

func (ch *CloudHandshake) Init(nodename string, creation uint32, enabledTLS bool) error {
return nil
}
func (ch *CloudHandshake) Start(c net.Conn) (node.ProtoOptions, error) {
return node.ProtoOptions{}, nil
}
3 changes: 2 additions & 1 deletion debug.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+build debug
//go:build debug
// +build debug

package ergo

Expand Down
36 changes: 34 additions & 2 deletions ergo.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,58 @@ package ergo
import (
"context"

"github.com/ergo-services/ergo/cloud"
"github.com/ergo-services/ergo/erlang"
"github.com/ergo-services/ergo/gen"
"github.com/ergo-services/ergo/node"
"github.com/ergo-services/ergo/proto/dist"
)

// StartNode create new node with name and cookie string
func StartNode(name string, cookie string, opts node.Options) (node.Node, error) {
return StartNodeWithContext(context.Background(), name, cookie, opts)
}

// CreateNodeWithContext create new node with specified context, name and cookie string
// StartNodeWithContext create new node with specified context, name and cookie string
func StartNodeWithContext(ctx context.Context, name string, cookie string, opts node.Options) (node.Node, error) {
version := node.Version{
Release: Version,
Prefix: VersionPrefix,
OTP: VersionOTP,
}
if opts.Env == nil {
opts.Env = make(map[gen.EnvKey]interface{})
}
opts.Env[node.EnvKeyVersion] = version

// add erlang support application
opts.Applications = append([]gen.ApplicationBehavior{&erlang.KernelApp{}}, opts.Applications...)

return node.StartWithContext(context.WithValue(ctx, "version", version), name, cookie, opts)
// add cloud support if it's enabled
if opts.Cloud.Enabled {
cloudApp := cloud.CreateApp(opts.Cloud)
opts.Applications = append([]gen.ApplicationBehavior{cloudApp}, opts.Applications...)
}

if opts.Handshake == nil {
handshakeOptions := dist.HandshakeOptions{
Cookie: cookie,
}
// create default handshake for the node (Erlang Dist Handshake)
opts.Handshake = dist.CreateHandshake(handshakeOptions)
}

if opts.Proto == nil {
// create default proto handler (Erlang Dist Proto)
protoOptions := node.DefaultProtoOptions()
protoOptions.Compression = opts.Compression
opts.Proto = dist.CreateProto(name, protoOptions)
}

if opts.StaticRoutesOnly == false && opts.Resolver == nil {
// create default resolver (with enabled Erlang EPMD server)
opts.Resolver = dist.CreateResolverWithEPMD(ctx, "", dist.DefaultEPMDPort)
}

return node.StartWithContext(ctx, name, cookie, opts)
}
6 changes: 3 additions & 3 deletions erlang/appmon.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type jobDetails struct {
}

// Init initializes process state using arbitrary arguments
// Init -> state
func (am *appMon) Init(process *gen.ServerProcess, args ...etf.Term) error {
lib.Log("APP_MON: Init %#v", args)
from := args[0]
Expand All @@ -37,10 +36,11 @@ func (am *appMon) Init(process *gen.ServerProcess, args ...etf.Term) error {
return nil
}

// HandleCast
func (am *appMon) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
var appState *appMonState = process.State.(*appMonState)
lib.Log("APP_MON: HandleCast: %#v", message)
node := process.Env("ergo:Node").(node.Node)
node := process.Env(node.EnvKeyNode).(node.Node)
switch message {
case "sendStat":

Expand Down Expand Up @@ -137,7 +137,7 @@ func (am *appMon) HandleCast(process *gen.ServerProcess, message etf.Term) gen.S
}

func (am *appMon) makeAppTree(process gen.Process, app etf.Atom) etf.Tuple {
node := process.Env("ergo:Node").(node.Node)
node := process.Env(node.EnvKeyNode).(node.Node)
appInfo, err := node.ApplicationInfo(string(app))
if err != nil {
return nil
Expand Down
2 changes: 2 additions & 0 deletions erlang/erlang.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ type erlang struct {
gen.Server
}

// Init
func (e *erlang) Init(process *gen.ServerProcess, args ...etf.Term) error {
lib.Log("ERLANG: Init: %#v", args)
return nil
}

// HandleCall
func (e *erlang) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
lib.Log("ERLANG: HandleCall: %#v, From: %#v", message, from)

Expand Down
1 change: 1 addition & 0 deletions erlang/global_name_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type globalNameServer struct {
gen.Server
}

// HandleCast
func (gns *globalNameServer) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
return gen.ServerStatusOK
}
19 changes: 13 additions & 6 deletions erlang/net_kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,54 @@ import (
"github.com/ergo-services/ergo/lib/osdep"
)

// KernelApp
type KernelApp struct {
gen.Application
}

// Load
func (nka *KernelApp) Load(args ...etf.Term) (gen.ApplicationSpec, error) {
return gen.ApplicationSpec{
Name: "erlang",
Description: "Erlang support app",
Version: "v.1.0",
Children: []gen.ApplicationChildSpec{
gen.ApplicationChildSpec{
{
Child: &netKernelSup{},
Name: "net_kernel_sup",
},
},
}, nil
}

// Start
func (nka *KernelApp) Start(p gen.Process, args ...etf.Term) {}

type netKernelSup struct {
gen.Supervisor
}

// Init
func (nks *netKernelSup) Init(args ...etf.Term) (gen.SupervisorSpec, error) {
return gen.SupervisorSpec{
Children: []gen.SupervisorChildSpec{
gen.SupervisorChildSpec{
{
Name: "net_kernel",
Child: &netKernel{},
},
gen.SupervisorChildSpec{
{
Name: "global_name_server",
Child: &globalNameServer{},
},
gen.SupervisorChildSpec{
{
Name: "rex",
Child: &rex{},
},
gen.SupervisorChildSpec{
{
Name: "observer_backend",
Child: &observerBackend{},
},
gen.SupervisorChildSpec{
{
Name: "erlang",
Child: &erlang{},
},
Expand All @@ -75,12 +79,14 @@ type netKernel struct {
routinesCtx map[etf.Pid]context.CancelFunc
}

// Init
func (nk *netKernel) Init(process *gen.ServerProcess, args ...etf.Term) error {
lib.Log("NET_KERNEL: Init: %#v", args)
nk.routinesCtx = make(map[etf.Pid]context.CancelFunc)
return nil
}

// HandleCall
func (nk *netKernel) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (reply etf.Term, status gen.ServerStatus) {
lib.Log("NET_KERNEL: HandleCall: %#v, From: %#v", message, from)
status = gen.ServerStatusOK
Expand Down Expand Up @@ -124,6 +130,7 @@ func (nk *netKernel) HandleCall(process *gen.ServerProcess, from gen.ServerFrom,
return
}

// HandleInfo
func (nk *netKernel) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
lib.Log("NET_KERNEL: HandleInfo: %#v", message)
switch m := message.(type) {
Expand Down
6 changes: 3 additions & 3 deletions erlang/observer_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ type observerBackend struct {
}

// Init initializes process state using arbitrary arguments
// Init(...) -> state
func (o *observerBackend) Init(process *gen.ServerProcess, args ...etf.Term) error {
lib.Log("OBSERVER: Init: %#v", args)

funProcLibInitialCall := func(a ...etf.Term) etf.Term {
return etf.Tuple{etf.Atom("proc_lib"), etf.Atom("init_p"), 5}
}
node := process.Env("ergo:Node").(node.Node)
node := process.Env(node.EnvKeyNode).(node.Node)
node.ProvideRPC("proc_lib", "translate_initial_call", funProcLibInitialCall)

funAppmonInfo := func(a ...etf.Term) etf.Term {
Expand All @@ -42,6 +41,7 @@ func (o *observerBackend) Init(process *gen.ServerProcess, args ...etf.Term) err
return nil
}

// HandleCall
func (o *observerBackend) HandleCall(state *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
lib.Log("OBSERVER: HandleCall: %v, From: %#v", message, from)
function := message.(etf.Tuple).Element(1).(etf.Atom)
Expand All @@ -68,7 +68,7 @@ func (o *observerBackend) HandleCall(state *gen.ServerProcess, from gen.ServerFr

func (o *observerBackend) sysInfo(p gen.Process) etf.List {
// observer_backend:sys_info()
node := p.Env("ergo:Node").(node.Node)
node := p.Env(node.EnvKeyNode).(node.Node)
processCount := etf.Tuple{etf.Atom("process_count"), len(p.ProcessList())}
processLimit := etf.Tuple{etf.Atom("process_limit"), 262144}
atomCount := etf.Tuple{etf.Atom("atom_count"), 0}
Expand Down
Loading

0 comments on commit c6a30bc

Please sign in to comment.