GithubHelp home page GithubHelp logo

iothub's People

Contributors

adriansmares avatar aka-mj avatar alexg-axis avatar amenzhinsky avatar beandrad avatar bocajim avatar brocaar avatar chrishayles avatar dependabot[bot] avatar diegosz avatar michaelbironneau avatar michaelperel avatar mikebarber1 avatar moqmar avatar shaunco avatar shiranr avatar tom5760 avatar whywaita avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

iothub's Issues

Possible change to direct methods

Does anyone have any inputs/objections to an alternate direct method implementation that can change the reply to be asynchronous from the callback? I have a use case where I need processing time to handle the callback and I don't want to hold the context, I want to send the reply at a later date.

Possible changes:

  1. Callback provides messageID and then a new function is added that sends a reply when that is invoked
  2. Callback provides a struct with a Reply() method for easy responses (but harder serialization to manage).

I prefer #1 because it is easy to pass the ID between async processing.

Support for OnConnection Lister in MQTT transport

Setting the OnConnection listener on the MQTT Transports breaks subscriptions, because the library relies on it, so it is impossible to get notifications about disconnect. For disconnects, it is possible to customize the OnConnectionLost as such:

opts := mqtt.WithClientOptionsConfig(func(opts *paho.ClientOptions) {
		opts.OnConnectionLost = func(client paho.Client, e error) {
			onDisconnect(e)
		}
	})

It would be nice if there was someway to get OnConnect callbacks.

Reconnecting with new credentials

I'm looking to see if it's possible to disconnect/reconnect with new credentials?
For a long running connection my x509 cert may expire and my program is able to acquire a new one but then I'll need to restart my connection with the new cert. Wondering if this is possible without creating a new client. So far I'm had no luck getting this to work. I'm currently trying to call Close() on the transport and then Connect() passing it the new credentials. After re-connection nothing is making it to the cloud.

Receiving C2D message for iotdevice gives message parse error

I'm trying to receive C2D messages. When I send the message from the Azure portal I get the following error:

2022/10/19 17:39:16 ERROR message parse error: invalid semicolon separator in query

Here is the program:

func main() {
	c, err := iotdevice.NewFromX509FromFile(iotmqtt.New(), "mydevice", "xxx", "xxx", "xxx")
	if err != nil {
		log.Fatal(err)
	}

	if err = c.Connect(context.Background()); err != nil {
		log.Fatal(err)
	}

	esub, err := c.SubscribeEvents(context.Background())
	go func() {
		for {
			msg := <-esub.C()
			fmt.Printf(">> %+v\n", msg)
		}
	}()

	termsig := make(chan os.Signal, 1)
	signal.Notify(termsig, syscall.SIGINT, syscall.SIGTERM)
	<-termsig
}

I tried sending ASCII text and JSON for the portal. How could I receive C2D messages? I'm looking to use the iotdevice module rather than the iotservice module.

Doesn't accept connection string without shared access key?

I'm trying to connect and it appears things are failing on the connection string. My connection string works with the C SDK.

This is the error I'm seeing:

2022/10/10 17:51:44 SharedAccessKey is required

My connection string:

HostName=decog-iothub-eastus-###.azure-devices.net;DeviceId=mjohn-1;x509=true

Connection drops after a while, how to refresh it

I'm creating a cloud-to-device link via AMQP with:

ihQueueClient, err := iotservice.NewFromConnectionString(iotHubConnStr)

I can use this successfully for 1 hour or so, but then after that I start seeing:

*Error{Condition: amqp:unauthorized-access, Description: Token or Certificate is invalid., Info: map[com.microsoft:is-filtered:true com.microsoft:tracking-id:<<<TRACKING_ID>>>-G:6-TimeStamp:02/10/2021 16:05:08]}

Looks like the AMQP connection is being dropped due to inactivity or just because 1 hour is passed after it has been created. Is there any way I can avoid this? How can I specify to automatically refresh or reconnect to the IoT Hub?

I can see in here

func WithTLSConfig(config *tls.Config) ClientOption {

there's this TLS option, but it's not exactly related to timeouts, that's more about extra security checks when using TLS:

// WithTLSConfig sets TLS config that's used by REST HTTP and AMQP clients.
func WithTLSConfig(config *tls.Config) ClientOption {
	return func(c *Client) {
		c.tls = config
	}
}

Support for Asynchronous handling of Direct Methods

Because of how The Direct Method handler is implemented, there is no opportunity for asynchrony without blocking concurrent or future direct method requests. Ideally, instead of :

type DirectMethodHandler func(p map[string]interface{}) (map[string]interface{}, error)

It was something like:

type DirectMethodHandler func(input map[string]interface{},completion func(map[string]interface{}, error))

Or something channel based.

Possible goroutine leaks in *Client.SendEvent()

Hi there, recently I found this SDK, and it's awesome! However, when I use *Client.SendEvent in iotservice package, I encountered a weird problem, 50 minutes after calling this function, a log comes out as follows:
image

2021/03/22 11:41:47 ERROR put token error: amqp: session closed

And I find a issue explaning this: #38 (comment) . As the comment explains, *Client.SendEvent will result in calling *Client.putTokenContinuously:

// putTokenContinuously in v0.7.0
func (c *Client) putTokenContinuously(ctx context.Context, conn *amqp.Client) error {
	const (
		tokenUpdateInterval = time.Hour

		// we need to update tokens before they expire to prevent disconnects
		// from azure, without interrupting the message flow
		tokenUpdateSpan = 10 * time.Minute
	)

	sess, err := conn.NewSession()
	if err != nil {
		return err
	}
	defer sess.Close(context.Background())

	if err := c.putToken(ctx, sess, tokenUpdateInterval); err != nil {
		return err
	}

	go func() {
		ticker := time.NewTimer(tokenUpdateInterval - tokenUpdateSpan)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				if err := c.putToken(context.Background(), sess, tokenUpdateInterval); err != nil {
					c.logger.Errorf("put token error: %s", err)
					return
				}
				ticker.Reset(tokenUpdateInterval - tokenUpdateSpan)
				c.logger.Debugf("token updated")
			case <-c.done:
				return
			}
		}
	}()
	return nil
}

This function will start a new goroutine to putToken to update session token every 50 minutes (tokenUpdateInterval - tokenUpdateSpan). However, defer sess.Close(context.Background()) means that the session will be closed when putTokenContinuously returns. As a result, putToken called in the goroutine will always fail (which will log: put token error: amqp: session closed). I notice that this problem has been fixed in recent commit (though not released yet), but here's another question:

Each time I call the *Client.SendEvent(), it will start a new session and start a goroutine to putToken every 50 minutes until the Client is closed, which means each time I send an event, a new endless goroutine is created to putToken continuously, but all I need is just sending an event, after that, I don't need to maintain this session anymore (because next time I call *Client.SendEvent(), it will start another new session for me). What's more, as I have to call *Client.SendEvent() frequently, it could lead to a large number of goroutine leak.
My solution to this problem is that the *Client.newSession() called by *Client.SendEvent() don't call putTokenContinuously, it just call putToken and return the new session.

Help sending from service to device

Hi,

I've been using this library for almost a year and find it very useful. But I am confused about a panic state I get when trying to send from service to device via iotservice.SendEvent()

I get the following log whenever SendEvent gets called:

D connecting to SERVER_NAME.azure-devices.net
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x10 pc=0x6fefe0]`

I presume I am not setting something correctly, but I'm not sure what.

Example code in the documentation would be helpful and appreciated.

Here is what I am doing:

var err error
iotServiceClient, err = iotservice.New(
	iotservice.WithConnectionString(IOT_SERVICE_CONNECTION_STRING),
        iotservice.WithLogger(common.NewLogWrapper(true)),
)	
if err != nil {
  log.Fatal("ioterr", err)
}
m := socketMessage{}
m.Command = "hello"
toBytes, err := json.Marshal(m)
if err != nil {
    log.Fatal("json", err)
}
iotServiceClient.SendEvent(context.Background(), "device123", toBytes)

Getting ../pkg/mod/github.com/amenzhinsky/[email protected]/eventhub/client.go:266:22: not enough arguments in call to msg.Accept on install command

I'm trying to install the cli with the command GO111MODULE=on go get -u github.com/amenzhinsky/iothub/cmd/{iothub-service,iothub-device}

the iothub-divice installation was successful, but the iothub-service won't install, any one with this behaviour?

this is the output:

GO111MODULE=on go get -u github.com/amenzhinsky/iothub/cmd/{iothub-service,iothub-device}
go: found github.com/amenzhinsky/iothub/cmd/iothub-device in github.com/amenzhinsky/iothub v0.6.0
go: found github.com/amenzhinsky/iothub/cmd/iothub-service in github.com/amenzhinsky/iothub v0.6.0
go: github.com/Azure/go-amqp upgrade => v0.13.1
go: github.com/pkg/errors upgrade => v0.9.1
go: golang.org/x/net upgrade => v0.0.0-20200707034311-ab3426394381

github.com/amenzhinsky/iothub/eventhub
../pkg/mod/github.com/amenzhinsky/[email protected]/eventhub/client.go:266:22: not enough arguments in call to msg.Accept
have ()
want (context.Context)

Non JSON method payload

Thank you for creating this library :)

I am using method payloads (and responses) that are not in JSON form, but base64 strings (strictly speaking still valid json) as my connected devices use cellular data, so I want to keep data usage to an absolute minimum. However, the MethodCall.Payload in this library is a map[string]interface{}. I forked your library to change it into just an interface{}.

Are you interested in a pull request? (and if so, would you prefer a new method (to keep it backwards compatible) or a change to MethodCall and MethodResponse?)

Fatal error link detached due to IdleTimerExpired

Version:

github.com/amenzhinsky/iothub v0.7.0

Error:

Link detached, reason: *Error{Condition: amqp:link:detach-forced, Description: The link 'G2:...' is force detached. Code: ServerError. Details: AmqpEventHubConsumer.IdleTimerExpired: Idle timeout: 00:30:00.

I am getting this error message and restarting the pod Kubernetes container frequently. I had this code working for a long time and it did not happen so frequently. The first time, I thought that it was idle, but I checked the last message received was one minute before and not 30 minutes, maybe I misunderstand the Azure concept of idle in the Iothub bus and be observing the wrong parameters.

My contantainer log is:

...
{"time":"2021-05-01T06:17:58.627919145Z", "message received"}
{"time":"2021-05-01T06:17:58.633331806Z", "message received"}
{"time":"2021-05-01T06:17:58.638524857Z", "message received"}
{"time":"2021-05-01T06:18:02.227702684Z","level":"FATAL","prefix":"-","file":"main.go","line":"47","message":"link detached, reason: *Error{Condition: amqp:link:detach-forced, Description: The link 'G2:omited' is force detached. Code: ServerError. Details: AmqpEventHubConsumer.IdleTimerExpired: Idle timeout: 00:30:00.}

My golang code is:

parentCtx, _ := context.WithCancel(context.Background())
log.Fatal(iotHub.SubscribeEvents(parentCtx, func(msg *iotservice.Event) error {
	err = json.Unmarshal(msg.Payload, &identifier)
	log.Info(" identifier :", identifier)
	if err == nil {
                 HandleID(identifier)
	} else {
		log.Error("could not marshing identifier: ", err)
	}
       return nil
}

I am considering doing something like the following draft, but a little afraid of losing messages, now if there is an error I see due to the container reinitialization and fix it as soon as possible to do not lose messages.

draft:

for {
       err = iotHub.SubscribeEvents(parentCtx, HandleFuncHere)
       if err != nil {
	    if err == context.DeadlineExceeded { // IdleTimerExpired?
                     log.Errorf("iothub idle timeout")
	    } else {
		    log.Fatal(err) // another error
	    }
       }
	continue
}

This is a reasonable solution? Did someone experience something similar?

I appreciate any help that someone provides to workaround or understand better this issue, thanks :)

D2C properties encoding

Version: v0.7.0
Transport: MQTT

Minimal example to reproduce.

func sendEvent(hub *iotdevice.Client) {
	_ := hub.SendEvent(context.Background(),
		[]byte("whatever"),
		iotdevice.WithSendProperties(
			map[string]string{
				"te st": "to st",
			},
		),
	)
}

Please notice, that custom property contains space (' ') in both key and value. It is not forbidden by IoT Hub messaging contract (https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-construct).
Attempt to send such message will result in infinite re-connect loop:

2021/10/28 15:50:06 DEBUG connection established
2021/10/28 15:50:06 DEBUG connection lost: EOF
2021/10/28 15:50:06 DEBUG connection established
2021/10/28 15:50:06 DEBUG connection lost: EOF
2021/10/28 15:50:07 DEBUG connection established
2021/10/28 15:50:07 DEBUG connection lost: read tcp 192.168.88.99:38798->40.113.176.167:8883: read: connection reset by peer
2021/10/28 15:50:07 DEBUG connection established
2021/10/28 15:50:07 DEBUG connection lost: EOF
2021/10/28 15:50:07 DEBUG connection established
2021/10/28 15:50:07 DEBUG connection lost: EOF
2021/10/28 15:50:08 DEBUG connection established
2021/10/28 15:50:08 DEBUG connection lost: read tcp 192.168.88.99:38804->40.113.176.167:8883: read: connection reset by peer
2021/10/28 15:50:08 DEBUG connection established
2021/10/28 15:50:08 DEBUG connection lost: EOF
2021/10/28 15:50:09 DEBUG connection established
2021/10/28 15:50:09 DEBUG connection lost: EOF
2021/10/28 15:50:09 DEBUG connection established
2021/10/28 15:50:09 DEBUG connection lost: EOF
2021/10/28 15:50:09 DEBUG connection established
2021/10/28 15:50:09 DEBUG connection lost: EOF
2021/10/28 15:50:09 DEBUG connection established
2021/10/28 15:50:09 DEBUG connection lost: EOF

This happens because in (github.com/amenzhinsky/[email protected]/iotdevice/transport/mqtt/mqtt.go), properties are being incorrectly encoded. Spaces are replaced with '+' char, which is a wildcard in MQTT protocol, and leads to immediate connection drop. Since D2C message was not sent, after re-connect library will attempt to push this message once again leading to another connection drop. Cycle repeats forever.

Incorrectly encoded topic looks like this: devices/my_device/messages/events/te+st=to+st
While Python and C++ SDKs produce correctly encoded: devices/my_device/messages/events/te%20st=to%20st

Suggested fix is to use encoding library different from 'net/url' or replace '+' with "%20" on top of it.

Failing to update reported twin state

I'm trying to update a field in my twin and I'm getting a 400 error back. I'm using MQTT.

"request failed with 400 response code"

The code:

	d, r, e := c.RetrieveTwinState(context.Background())
	if e != nil {
		log.Errorw("Failed to retrieve twin", "error", e)
	}
	fmt.Printf("DESIRED: %+v\nREPORTED: %+v\n", d, r)

	r["lastConnectionTime"] = time.Now().UTC().Format(time.RFC3339)

	if v, e := c.UpdateTwinState(context.Background(), r); e != nil {
		log.Errorw("Failed to update twin", "error", e)
	} else {
		log.Debugw("Successfully updated twin", "version", v)
	}

Output:

DESIRED: map[$version:1]
REPORTED: map[$version:106 deviceInfo:map[components:[map[hwpn:000-00000-00 hwrev:000 infoelem:0 nodeid:17 serialnum:0 swpn:081-10010-00 swrev:00.05.00 typeid:0]] timestamp:2022-10-20T18:13:38Z] lastConnectionTime:2022-10-20T17:32:46+00:00Z powerFailure:map[timestamp:2022-10-20T14:21:40Z] productType:245]
{"level":"error","ts":1666290220.208017,"logger":"main.heartbeat","caller":"azure-go-telem/heartbeat.go:22","msg":"Failed to update twin","error":"request failed with 400 response code","stacktrace":"main.heartbeat\n\t/home/mjohn/workspace/connectivity-module/apps/azure-go-telem/heartbeat.go:22"}

CreationTimeUtc is not handled in message

Device can buffer up messages and send them all at some frequency. To accomplish, you can set CreationTimeUtc (payload creation time) in the event message. common.Message has this field, but looks like it is not set in the transport.send() https://github.com/amenzhinsky/iothub/blob/master/iotdevice/transport/mqtt/mqtt.go#L480
You need to set "$.ctime". Similarly other properties need to be honored like https://github.com/Azure/azure-iot-sdk-csharp/blob/master/iothub/device/src/Transport/Mqtt/MqttIotHubAdapter.cs#L1197

New tag for the current state

Hi,
I was just running into issue due to the behaviour of Go Modules. It will grab the latest tag and not the latest commit. So people will run maybe as I into problems that the function iotservice.FromConnectionString() is not defined.

Cheers!

amqp:link:redirect error while using example code

Hi,
I was just using your example code for the service component and received an amqp:link:redirect error. In the documentation of AMQP this error is about the problem of not resolving the address to the container but everything in the response map look okay to me.

I just set up a fresh IoT Hub and created a device by hand and trying to run those examples on my local machine. The device code is working.

Any hints? :)

Support for IoT Hub query language for device and module twins, jobs, and message routing

Is it possible to perform query requests now or is there any consideration to implement a query language feature?

as described here

I am figuring out a way to get modules and/or devices that are currently connected to your edgeHub. For that, I am doing GetModuleTwin requests for each device. With a query, I could save some requests.

https://stackoverflow.com/questions/65014114/what-is-connected-client-count-on-azure-iot-edge-dashboard

If there is no implementation for that and it is considered a useful feature, I would like to develop it :)

x509: certificate signed by unknown authority

I have an application that was working since September 2020, but on January 13 it stopped :/

I am trying to 'SubscribeEvents' and I get this error "x509: certificate signed by unknown authority".

I can connect IoTservice.NewFromConnectionString(MyConnectionString), but when I subscribe to events I got this error.

I would appreciate any help to configure it and make it works again.

Unneeded timeout

Hi.

In our project I've faced with 30s timeout when twin updates. But in transport setting and context I set 2 minutes. I've found the following code. Is it really need this constant timeout?

Direct Methods only support map[string]interface{}

Azure, and specifically IOT Central, supports numbers/strings/bools as direct method payloads, which don't work in the marshaling layer here. One option would be to defer marshal/unmarshal to the implementer of the DirectMethodFunc. Maybe this could be handled in conjunction with #23 - there could be something like RegisterDirectMethodAdvanced that support asynchrony and did bytes in, bytes out.

Parsing the Request ID for direct methods fails

My device is setup using a Device Provisioning Service. I'm using ModuleClient to register a direct method. We get the auth from NewModuleFromEnvironment

On callback I get the following error while parsing the request id

ERROR parse error: $rid parse error: strconv.ParseInt: parsing "327358f7-b968-4f62-a8e5-8fb0cda316d4": invalid syntax.

When using the NewModuleFromConnectionString everything works fine so far. Any pointers on how to fix this with the DPS?

Finalize the APIs

The TODO section mentions that the APIs are still not finalized.

I found an interface in the official Azure Go SDK which might help you in finalizing the APIs.
Take a look at this interface.

EDIT:
Although, there are no APIs specific for devices. But we can reuse the Naming Convention and several keywords which are used throughout Azure SDK.

AMQP Link Detach

I have an issue where I'm unable to publish events. Unfortunately I can't identify any more related circumstances than that. It has occurred some times, but in most cases it works as expected.

In essence the code works as follows:

ctx := context.Background()
message := []byte("Hello, World!")
expiry := 10 *60 * time.Second
deviceId := "some-device"

if err := client.SendEvent(
  ctx,
  deviceId,
  message,
  iotservice.WithSendAck((iotservice.AckType)("full")), 
  iotservice.WithSendExpiryTime(time.Now().Add(expiry)),
  ); err != nil {
  return err
}

The error is the following:

link detached, reason: *Error{Condition: amqp:link:detach-forced, Description: Server Busy. Please retry operation, Info: map[]}

The Java SDK seems to have this comment regarding the error:

  /**
     * An operator intervened to detach for some reason.
     */
    LINK_DETACH_FORCED("amqp:link:detach-forced"),

Same with the JS one: https://github.com/Azure/amqp-common-js/blob/master/lib/errors.ts#L171.

So to me it seems as if this error may occur from time to time. For me, it has always been solved with a restart, so I assume one way to handle it is to simply reconnect the client.

Possible to register a new device?

Is this possible to do in code, and if so are there plans to add this feature?

I am trying to avoid having to manually register every IOT device with azure.

Subscribe to C2D events throws error while receiving the events on device side

Go Version: go 1.19

ERROR message parse error: invalid semicolon separator in query

      c, err := iotdevice.NewFromConnectionString(
		iotmqtt.New(), "xxxxxxxxxxxxxxxxxxxx",
	)
	if err != nil {
		log.Fatal(err)
	}

	// connect to the iothub
	if err = c.Connect(context.Background()); err != nil {
		log.Fatal(err)
	}

	// receive a cloud-to-device message
	eventSub, err := c.SubscribeEvents(context.Background())

	for msg := range eventSub.C() {
		fmt.Println(msg.Payload)
	}

	if err := eventSub.Err(); err != nil {
		log.Fatal(err)
	}

Panic on received message

panic: interface conversion: interface {} is nil, not string

goroutine 204 [running]:
github.com/amenzhinsky/iothub/common/commonamqp.FromAMQPMessage(0xc00040cbd0, 0x1)
        /tmp/iothub/common/commonamqp/message.go:51 +0xa68
github.com/amenzhinsky/iothub/iotservice.(*Client).SubscribeEvents.func1(0xc00040cbd0)
        /tmp/iothub/iotservice/client.go:208 +0x34
created by github.com/amenzhinsky/iothub/eventhub.SubscribePartitions
        /tmp/iothub/eventhub/client.go:132 +0x1e9

This is because the value is not a string:

https://github.com/amenzhinsky/iothub/blob/master/common/commonamqp/message.go#L46

fmt.Printf("%+v", msg.ApplicationProperties) returns:

map[stats:<nil>]

This happends when a device sends a message (using MQTT) to the following topic: devices/DEVICEID/messages/events/stats

Send a message from a device to the hub

I was trying to send a message from a device running a module (my go application) to the IoT hub.

On the device I have iotedge installed in version 1.0.10.1. At first I tried to build the sample, provided in the readme:

package main

import (
	"context"
	"log"
	"os"

	"github.com/amenzhinsky/iothub/iotdevice"
	iotmqtt "github.com/amenzhinsky/iothub/iotdevice/transport/mqtt"
)

func main() {
	c, err := iotdevice.NewFromConnectionString(
		iotmqtt.New(), os.Getenv("IOTHUB_DEVICE_CONNECTION_STRING"),
	)
	if err != nil {
		log.Fatal(err)
	}

	// connect to the iothub
	if err = c.Connect(context.Background()); err != nil {
		log.Fatal(err)
	}

	// send a device-to-cloud message
	if err = c.SendEvent(context.Background(), []byte(`hello`)); err != nil {
		log.Fatal(err)
	}
}

Even though this works, it requires me to add the connection string to the environment variables of my container. On a container for a module I have the following environment variables set:

  • IOTEDGE_APIVERSION
  • IOTEDGE_AUTHSCHEME
  • IOTEDGE_DEVICEID
  • IOTEDGE_GATEWAYHOSTNAME
  • IOTEDGE_IOTHUBHOSTNAME
  • IOTEDGE_MODULEGENERATIONID
  • IOTEDGE_MODULEID
  • IOTEDGE_WORKLOADURI
  • RuntimeLogLevel
  • PATH

After looking a bit around in the code, I found the function NewModuleFromEnvironment() which is reading most of those variables, so I adjusted the code and tried to run it:

package main

import (
	"context"
	"log"

	"github.com/amenzhinsky/iothub/iotdevice"
	iotmqtt "github.com/amenzhinsky/iothub/iotdevice/transport/mqtt"
)

func main() {
	c, err := iotdevice.NewModuleFromEnvironment(
		iotmqtt.New(),
		false,
	)
	if err != nil {
		log.Fatal(err)
	}

	// connect to the iothub
	if err = c.Connect(context.Background()); err != nil {
		log.Fatal(err)
	}

	// send a device-to-cloud message
	if err = c.SendEvent(context.Background(), []byte(`hello`)); err != nil {
		log.Fatal(err)
	}
}

My application always exits with:

2020/11/12 15:15:02 Connect:
2020/11/12 15:15:02 not Authorized

And I'm unable to tell what part is missing. Other packages can send messages quite fine when only the selected settings are provided. Any idea how I can send a message from a Go module without providing the connection string to each and every module?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.