FreePBX Go port and license question

Hi all,

I have been working on a library, a Go port on a part of FreePBX on and off since last year, specifically on the modules by taking configuration input and turn them into an Asterisk text output.

Currently it can do the following

  • dialplan
  • announcement
  • callrecording
  • daynight
  • ivr
  • parking
  • ringgroup
  • systemrecording

The plan is to port the following modules and write more unit tests to cover more input combinations.

  • queue
  • extensions
  • feature codes
  • time conditions
  • time groups
  • misc destinations
  • trunks

It is 100% in Go language. I have 129 unit tests so far, covering all files at 89% coverage. Some snippets:
(repos not pushed yet)

import (
    "fmt"

    arw "github.com/gmhafiz/asterisk_rw"
    "github.com/gmhafiz/asterisk_rw/module"
)

func main() {
  
    // create a new announcement input request. 
	a := &module.Announcement{
		ID:                    1,
		Description:           "test description",
		CallRecordingFileName: "test.WAV",
		AllowSkip:             false,
		PostDestination:       "app-blackhole,hangup,1,",
		ReturnIvr:             false,
		NoAnswer:              false,
		RepeatMessage:         "",
	}

    // create an asterisk configuration setting
    created, _ := a.Create()
    
    fmt.Println(created)
}

output

[app-Announcement-1]
exten => s,1,GotoIf($["${CHANNEL(state)}" = "Up"]?begin)
exten => s,n,Answer
exten => s,n,Wait(1)
exten => s,n(begin),Noop(test description)
exten => s,n,Playback(custom/test.WAV,noanswer)
exten => s,n,Goto(app-blackhole,hangup,1,)

For unit tests, the test cases are designed around table-driven unit tests. Once the cases are added to the table, we loop through and then compare the expected strings against the output.

type test struct {
		name  string
		input Announcement
		want  string
	}

	tableTests := []test{
		{
			"no answer",
			Announcement{
				ID:                    1,
				Description:           "a1",
				CallRecordingID:       1,
				CallRecordingFileName: "file_example_WAV_1MG",
				AllowSkip:             false,
				PostDestination:       "app-blackhole,hangup,1",
				ReturnIvr:             false,
				NoAnswer:              false,
				RepeatMessage:         "", // disable
			},
		},
	}

	for _, test := range tableTests {
		t.Run(test.name, func(t *testing.T) {
			got, err := test.input.Create()
			if err != nil {
				t.Error(err)
			}

			if got != test.want {
				fmt.Println("got:")
				fmt.Println(got)
				fmt.Println("want:")
				fmt.Println(test.want)
				t.Error()
			}
		})
	}

The Create() method is done by translating from the freepbx modules:

const (
	extensionS = "s"
)

// Create first creates an in-memory model representation of the data before
// returning (string, error)
func (a *Announcement) Create() (string, error) {
	var ext extension.Extension

	section := a.CreateSection()
	ext.AddSection(section)
	if !a.NoAnswer {
		ext.Add(conf.New(section, extensionS, "", dialplan.GotoIf(`$["${CHANNEL(state)}" = "Up"]`, "begin", "")))
		ext.Add(conf.New(section, extensionS, "", dialplan.Answer()))
		ext.Add(conf.New(section, extensionS, "", dialplan.Wait(1)))
	} else {
		ext.Add(conf.New(section, extensionS, "", dialplan.Progress()))
	}
}

etc...

Thanks to the statically typed language, we can make sure each parameter of the methods are of correct types.

IDE on the other hand, helps with empty strings

image

The reason why we are porting to Go is that our stack is primarily in that language. Porting this, removes the dependency of a whole freepbx project as I primarily only need the modules functionalities.


I am going to publish this library. My question is that some modules are GPL while others are AGPL like callrecording module. I have all the modules in one folder and I included the GPL LICENSE file. I am not sure if I have to rename the AGPL LICENSE file when including it.

module
 |
 -- extension
   |
   -- announcement.go 
   -- announcement_test.go 
   -- callrecording.go 
   -- callrecording_test.go 
   -- dayNight.go 
   -- dayNight_test.go 
   -- LICENSE
   -- etc...

An alternative is to make a directory for each module so that I can put the correct LICENSE file in each folder.


On top of this library, I also have a gRPC(and HTTP) server project that includes this library. The purpose of this one is to act as a microservice, and it interacts with database. So that will be open source too. I am not sure on where to place these LICENSE files.


One other thing is the name of this library, asterisk_rw which people could confuse that it is an official product from Sangoma. I believe it could violate Sangoma’s copyright. As I haven’t pushed this repository yet, I can still change the name of this library.

2 Likes

Standard Disclaimer: I am not a lawyer and this is NOT legal advice. Sangoma has actual lawyers you may want to consult one

So FreePBX and Asterisk are trademarks. That means you can use them in the manor outlined in their trademark policy or in things classified as “fair use”

If you are using any of the FreePBX code you must follow copyright and licensing rules and attribute appropriately.

FreePBX is more than a code generator. If you are simply duplicating functionality I would avoid using the FreePBX trademark. Just do GoPBX or something more creative.

Some of the FreePBX code base is over 10 years old and some of the design choices were made based on restrictions such as PHP versions. You may actually find better ways to do certain things.

I am not a golang guy but I am curious to see the code of end result. I like new toys :slight_smile:

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.