Search Results

TIBCO FTL® Go Quick Start

Quick Start Contents

Introduction

This quick start guide focuses on a pair of TIBCO FTL sample applications written specifically for TIBCO Cloud Messaging (TCM): one publisher and one subscriber. The two applications also work with the TCM Demo.

Getting Started

Follow the steps below to get started using the sample applications:

  • Download and install the TIBCO FTL Messaging SDK and Go TCM Samples. This guide will refer to your FTL installation location as <ftl> and the sample location as <ftl-sample-path>.
  • The sample download contains the source for two Go sample applications.
  • Download and install Go 1.13+.
  • Download your tcm-config.yaml (look for this icon ). This guide will refer to the tcm-config.yaml download locations as <tcm-config>. The sample applications do not take any arguments, instead they require your tcm-config.yaml to be present in the current working directory.
  • On Linux and macOS, add the <ftl>/<version>/bin and <ftl>/<version>/lib directories to your path and library path respectively. On Windows you only need to add <ftl>/<version>/bin to your path.
  • On Linux and macOS source the setup script: source <ftl>/<version>/samples/setup. On Windows run <ftl>\<version>\samples\setup.bat.
  • Copy the <ftl-sample-path>/go/src/tibco.com/tcm directory from the FTL samples package into the <ftl>/<version>/samples/src/golang/src/tibco.com directory installed by the FTL messaging SDK package.

Documentation

The godoc utility can be used to serve up the TIBCO documentation for Go:

  1. Set GOPATH to <ftl>/<version>/samples/golang
  2. Run go get golang.org/x/tools/cmd/godoc
  3. Run godoc -http=:6060
  4. Browse to http://localhost:6060/pkg/tibco.com

Building and running samples

The Go samples package does not come with pre-built samples. Below are the instructions for building the samples from the source files included in the samples download.

Linux and macOS

> export GOPATH=<ftl>/<version>/samples/src/golang
> source <ftl>/<version>/samples/setup
> cp -r <ftl-sample-path>/go/src/tibco.com/tcm $GOPATH/src/tibco.com
> go get gopkg.in/yaml.v3
> go install tibco.com/ftl...
> go install tibco.com/tcm...
> export PATH=$GOPATH/bin:$PATH
> export LD_LIBRARY_PATH=<ftl>/<version>/lib
> cp <tcm-config> $PWD
> tcmdemopub

Windows

For Windows please make sure you have mingw64 (5.3 or greater) installed and the PATH environment variable includes the path to the gcc compiler from the mingw64 installation.

> set GOPATH=<ftl>\<version>\samples\src\golang
> <ftl>\<version>\samples\setup.bat
> xcopy /E /I <ftl-sample-path>\go\src\tibco.com\tcm %GOPATH%\src\tibco.com\tcm
> go get gopkg.in/yaml.v3
> go install tibco.com/ftl...
> go install tibco.com/tcm...
> set PATH=%GOPATH%\bin;%PATH%
> copy <tcm-config> %CD%
> tcmdemopub

Description of sample applications

Publisher

Basic publisher program that demonstrates the use of publishing FTL messages.

Subscriber

Basic subscriber program that demonstrates the use of subscribing to FTL messages.

Run the Subscriber and Publisher at the same time to demonstrate real-time messaging. Stop the Subscriber, run the Publisher, and restart the Subscriber to demonstrate persistence.

Using the FTL SDK

To use the FTL SDK include the library and any third-party dependencies in your source files:

import "tibco.com/ftl"
import "gopkg.in/yaml.v3"

CGO

FTL GO applications depend on native C libraries (CGO). Instructions for configuring CGO can be found in the GO sample directory of the GO SDK download.

Client Configuration

The client configuration used by the sample applications is located in the tcm-config.yaml file. The Go sample uses a third-party YAML parser. You can fetch this YAML library using go get gopkg.in/yaml.v3.

type tcmOptions struct {
	FtlURL  string `yaml:"ftl_url"`
	AuthID  string `yaml:"tcm_authentication_id"`
	AuthKey string `yaml:"tcm_authentication_key"`
	AppName string `yaml:"ftl_application"`
	Cert    string `yaml:"ftl_certificate"`
}

func parseAppConfig() (tcmOptions, error) {
	var options tcmOptions

	// Read configuration file
	yamlFile, err := ioutil.ReadFile("tcm-config.yaml")
	if err != nil {
		return options, fmt.Errorf("Failed to read configuration file: %s", err)
	}

	err = yaml.Unmarshal(yamlFile, &options)
	if err != nil {
		return options, fmt.Errorf("Failed to load configuration options: %s", err)
	}

	if options.FtlURL == "" {
		return options, fmt.Errorf("Failed to load realm URL from configuration file")
	}

	if options.AuthKey == "" {
		return options, fmt.Errorf("Failed to load authentication key from configuration file")
	}
	if options.AuthID == "" {
		return options, fmt.Errorf("Failed to load authentication id from configuration file")
	}

	if options.Cert == "" {
		return options, fmt.Errorf("Failed to load server certificate from configuration file")
	}

	options.Cert = strings.ReplaceAll(options.Cert, "\\n", "\n")

	return options, nil
}

Configuring FTL Realm Properties

A properties object allows the client application to set attributes (or properties) for an object when the object is created. Declare realm property variables:

realmProps = make(ftl.Props)

A unique client label for each application will make tracking and monitoring easier.

realmProps[ftl.RealmPropertyStringClientLabel] = "tcmdemopub.go"

Configuring TCM authentication and server verification

Authentication using TCM specific authentication keys is required. The authentication id and key are located in the tcm-config.yaml.

realmProps[ftl.RealmPropertyStringUsername] = options.AuthID
realmProps[ftl.RealmPropertyStringUserpassword] = options.AuthKey

Use the trust file PEM certificate included in the tcm-config.yaml to verify the server you are Connect too. The PEM string contained in the tcm-config.yaml is modified to fit on a single line. Replace the ‘\n’ substring with a newline character to obtain a legal PEM string.

realmProps[ftl.RealmPropertyLongTrustType] = ftl.RealmHTTPSConnectionUseSpecifiedTrustString
realmProps[ftl.RealmPropertyStringTrustPemString] = options.Cert

Establishing a connection

Establish a connection to TCM. Specify a string containing the realm service URL, a string containing the application name, and the properties object created above. All values required for a FTL realm connection are contained in the tcm-config.yaml

realm, err := ftl.Connect(options.FtlURL, options.AppName, realmProps)

Publishing a message

Before a message can be published, the publisher must be created on the previously-created realm. Specify the endpoint onto which the messages will be published. In this example we are using the “default” endpoint.

pub, err := realm.NewPublisher("default", nil)

In order to send a message, the message object must first be created via a call to realm.CreateMessage(). Specify the format name. Here the format “demo_tcm” is used. TCM only supports dynamic formats.

msg, err := realm.NewMessage("demo_tcm")

A newly-created message is empty - it contains no fields. The next step is to add one or more fields to the message. msg.SetString adds a string field. In this example a string field named demo_tcm is added, with the value “message seq”.

content := struct {
    DemoTcm string `ftl:"demo_tcm"`
}{
    DemoTcm: fmt.Sprintf("message %d", seq),
}
err = msg.Marshal(&content)

Once the message is complete, it can be sent via pub.Send. Specify the message to be sent.

err = pub.Send(msg)

Subscribing and receiving messages

Event Queue

An event queue is required to facilitate message dispatching. Since creating the queue object implicitly also creates a thread from which to dispatch the queue, an error channel is used to notify the client application of any errors detected by the event queue dispatch thread.

errChan := make(chan error)
queue, err = realm.NewQueue(errChan, nil)

Subscriber

Create the subscriber object by specifying the endpoint name, an optional content matcher, an optional properties object and the message channel.

sub, err = queue.Subscribe("default", matcher, subscriberProps, msgChan)

Endpoints

TIBCO Cloud messaging only supports a fixed set of endpoints: default, shared, last-value and map. Each endpoint is associated with a durable type of the same name. If your application does not need persistence use the default endpoint.

Content Matcher

A content matcher is used to limit which messages are delivered to a client application based on the content of the message. In this case, {"demo_tcm":true} matches any message which contains the field demo_tcm.

matcher := `{"demo_tcm":true}`

Subscriber Properties

A shared durable essentially acts like a queue. Messages are stored in the persistent server, and apportioned among active subscribers to the durable in a round-robin fashion. Each subscriber must specify the same durable name. The durable name is defined by properties specified when the subscriber is created. If your application does not need persistence do not supply a durable name.

subscriberProps := make(ftl.Props)
subscriberProps[ftl.SubscriberPropertyStringDurableName] = "tcmdemosub.go"

Message Channel

Messages are delivered to the client application through a channel. This channel must be created by the client application, and provided to the event queue when creating a subscriber. This is analogous to specifying the message delivery callback function in the C API. Continuing with the analogy, specifying separate message delivery callback functions for different subscribers in the C API would require creating and servicing multiple channels in go.

msgChan := make(chan ftl.Message)

Subscribing to Notifications

All asynchronous events are communicated from the FTL API to go via channels. This includes message delivery and notifications.

notificationChan := make(chan ftl.Notification)
realm.SetNotificatonChannel(notificationChan)

Dispatching

signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
Loop:
	for {
		select {
		case err := <-errChan:
			log.Printf("received message on error channel: %s", err)
			break Loop
		case note := <-notificationChan:
			log.Printf("received message on notification channel: %s", note)
			break Loop
		case <-signals:
			break Loop
		case msg := <-msgChan:
			content := struct {
				DemoTcm string `ftl:"demo_tcm"`
			}{}
			err := msg.Unmarshal(&content)
			if err != nil {
				log.Fatal(ftl.ErrStack(err))
			}
			log.Printf("Received %v\n", msg)
		}
	}

Cleanup

Once objects are no longer needed, they should be disposed of - and generally in reverse order of creation.

Publisher

msg.Destroy();
pub.Close()
realm.Close();

Subscriber

queue.CloseSubscription(sub)
close(msgChan)
queue.Destroy()
close(errChan)
realm.Close();

To permanently destroy a durable subscription, including any messages stored by TIBCO Cloud Messaging for that durable, first close the subscription and then call unsubscribe using the realm object. Supply the unsubscribe call with the endpoint name and durable name used to create the durable subscription.

queue.CloseSubscription(sub)
realm.Unsubscribe("default", "tcmdemosub.go")