Code Monkey home page Code Monkey logo

go-fcm's Introduction

go-fcm

GoDoc Lint and Testing Go Report Card

This project was forked from github.com/edganiukov/fcm.

More information on Firebase Cloud Messaging

Feature

  • Send messages to a single device
  • Send messages to a multiple devices
  • Send messages to a topic
  • Supports condition attribute

Getting Started

To install fcm, use go get:

go get github.com/appleboy/go-fcm

Provide credentials using ADC

Google Application Default Credentials (ADC) for Firebase projects support Google service accounts, which you can use to call Firebase server APIs from your app server or trusted environment. If you're developing code locally or deploying your application on-premises, you can use credentials obtained via this service account to authorize server requests.

To authenticate a service account and authorize it to access Firebase services, you must generate a private key file in JSON format.

To generate a private key file for your service account:

  1. In the Firebase console, open Settings > Service Accounts.
  2. Click Generate New Private Key, then confirm by clicking Generate Key.
  3. Securely store the JSON file containing the key.

When authorizing via a service account, you have two choices for providing the credentials to your application. You can either set the GOOGLE_APPLICATION_CREDENTIALS environment variable, or you can explicitly pass the path to the service account key in code. The first option is more secure and is strongly recommended.

See the more detail information here.

Usage

Here is a simple example illustrating how to use FCM library:

package main

import (
  "context"
  "fmt"
  "log"

  "firebase.google.com/go/v4/messaging"
  fcm "github.com/appleboy/go-fcm"
)

func main() {
  ctx := context.Background()
  client, err := fcm.NewClient(
    ctx,
    fcm.WithCredentialsFile("path/to/serviceAccountKey.json"),
    // initial with service account
    // fcm.WithServiceAccount("[email protected]"),
  )
  if err != nil {
    log.Fatal(err)
  }

  // Send to a single device
  token := "test"
  resp, err := client.Send(
    ctx,
    &messaging.Message{
      Token: token,
      Data: map[string]string{
        "foo": "bar",
      },
    },
  )
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println("success count:", resp.SuccessCount)
  fmt.Println("failure count:", resp.FailureCount)
  fmt.Println("message id:", resp.Responses[0].MessageID)
  fmt.Println("error msg:", resp.Responses[0].Error)

  // Send to topic
  resp, err = client.Send(
    ctx,
    &messaging.Message{
      Data: map[string]string{
        "foo": "bar",
      },
      Topic: "highScores",
    },
  )
  if err != nil {
    log.Fatal(err)
  }

  // Send with condition
  // Define a condition which will send to devices which are subscribed
  // to either the Google stock or the tech industry topics.
  condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

  // See documentation on defining a message payload.
  message := &messaging.Message{
    Data: map[string]string{
      "score": "850",
      "time":  "2:45",
    },
    Condition: condition,
  }

  resp, err = client.Send(
    ctx,
    message,
  )
  if err != nil {
    log.Fatal(err)
  }

  // Send multiple messages to device
  // Create a list containing up to 500 messages.
  registrationToken := "YOUR_REGISTRATION_TOKEN"
  messages := []*messaging.Message{
    {
      Notification: &messaging.Notification{
        Title: "Price drop",
        Body:  "5% off all electronics",
      },
      Token: registrationToken,
    },
    {
      Notification: &messaging.Notification{
        Title: "Price drop",
        Body:  "2% off all books",
      },
      Topic: "readers-club",
    },
  }
  resp, err = client.Send(
    ctx,
    messages...,
  )
  if err != nil {
    log.Fatal(err)
  }

  // Send multicast message
  // Create a list containing up to 500 registration tokens.
  // This registration tokens come from the client FCM SDKs.
  registrationTokens := []string{
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n",
  }
  msg := &messaging.MulticastMessage{
    Data: map[string]string{
      "score": "850",
      "time":  "2:45",
    },
    Tokens: registrationTokens,
  }
  resp, err = client.SendMulticast(
    ctx,
    msg,
  )
  if err != nil {
    log.Fatal(err)
  }

  fmt.Printf("%d messages were sent successfully\n", resp.SuccessCount)
  if resp.FailureCount > 0 {
    var failedTokens []string
    for idx, resp := range resp.Responses {
      if !resp.Success {
        // The order of responses corresponds to the order of the registration tokens.
        failedTokens = append(failedTokens, registrationTokens[idx])
      }
    }

    fmt.Printf("List of tokens that caused failures: %v\n", failedTokens)
  }
}

Custom HTTP Client

You can use a custom HTTP client by passing it to the NewClient function:

func main() {
  httpTimeout := time.Duration(5) * time.Second
  tlsTimeout := time.Duration(5) * time.Second

  transport := &http2.Transport{
    DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
      return tls.DialWithDialer(&net.Dialer{Timeout: tlsTimeout}, network, addr, cfg)
    },
  }

  httpClient := &http.Client{
    Transport: transport,
    Timeout:   httpTimeout,
  }

  ctx := context.Background()
  client, err := fcm.NewClient(
    ctx,
    fcm.WithCredentialsFile("path/to/serviceAccountKey.json"),
    fcm.WithHTTPClient(httpClient),
  )
}

Custom Proxy Server

You can use a custom proxy server by passing it to the NewClient function:

func main() {
  ctx := context.Background()
  client, err := fcm.NewClient(
    ctx,
    fcm.WithCredentialsFile("path/to/serviceAccountKey.json"),
    fcm.WithHTTPProxy("http://localhost:8088"),
  )
}

Mock Client for Testing

You can use a mock client for Unit Testing by initializing your NewClient with the following:

  • fcm.WithEndpoint with a local httptest.NewServer URL
  • fcm.WithProjectID any string
  • fcm.WithServiceAccount any string
  • fcm.WithCustomClientOption with option option.WithoutAuthentication()
package main

import (
  "context"
  "net/http"
  "net/http/httptest"
  "testing"

  "firebase.google.com/go/v4/messaging"
  fcm "github.com/appleboy/go-fcm"
  "google.golang.org/api/option"
)

func TestMockClient(t *testing.T) {
  server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "application/json")
    _, _ = w.Write([]byte(`{
      "name": "q1w2e3r4"
    }`))
  }))
  defer server.Close()

  client, err := fcm.NewClient(
    context.Background(),
    fcm.WithEndpoint(server.URL),
    fcm.WithProjectID("test"),
    fcm.WithCustomClientOption(option.WithoutAuthentication()),
  )
  if err != nil {
    t.Fatalf("unexpected error: %v", err)
  }
  resp, err := client.Send(
    context.Background(),
    &messaging.Message{
      Token: "test",
      Data: map[string]string{
        "foo": "bar",
      },
    })
  if err != nil {
    t.Fatalf("unexpected error: %v", err)
  }
  checkSuccessfulBatchResponseForSendEach(t, resp)
}

func checkSuccessfulBatchResponseForSendEach(t *testing.T, resp *messaging.BatchResponse) {
  if resp.SuccessCount != 1 {
    t.Fatalf("expected 1 successes\ngot: %d sucesses", resp.SuccessCount)
  }
  if resp.FailureCount != 0 {
    t.Fatalf("expected 0 failures\ngot: %d failures", resp.FailureCount)
  }
}

go-fcm's People

Contributors

appleboy avatar befy avatar brandesign avatar edpelesh avatar gbhrdt avatar joel-stripe avatar netrebel avatar novalagung avatar rostopira avatar sebastienmelki avatar thedevsaddam avatar yokotaso 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  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  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-fcm's Issues

Critical sound

How can I set "critical" key for sound object for IOS Notifications?

"sound": {  
    "critical": 1,
}

net/http: TLS handshake timeout

`message := &fcm.Message{
To: firebaseID,
Notification: &fcm.Notification{
Title: "New Notification",
Body: contentMessage,
},
}

response, err := fcmClient.Send(message)
if err != nil {
	return err
}`

when this part has been run after seconds this error returned :
net/http: TLS handshake timeout
what is propblem ?

Error installing

Hello all,

I got this error installing the library

pi@raspberrypi:~ $ go version
go version go1.17.3 linux/arm
pi@raspberrypi:~ $ go get github.com/appleboy/go-fcm

runtime/internal/sys

/usr/local/go/src/runtime/internal/sys/stubs.go:9:7: PtrSize redeclared in this block
/usr/local/go/src/runtime/internal/sys/arch.go:24:38: previous declaration
/usr/local/go/src/runtime/internal/sys/stubs.go:10:24: undefined: Uintreg

someone can hel p me ?

Regards

Mirko

Send to topic is failing

I am successfully using the library for sending the Firebase cloud messages to individual devices with FCM token.

However, sending message to topic fails with following response :

&{Ok:true StatusCode:200 MulticastId:6658460146703210078 Success:0 Fail:1 Canonical_ids:0 Results:[map[error:InvalidRegistrat ion]] MsgId:0 Err: RetryAfter:}

I am unable to understand the reason behind it from the response.

Thank you

FCM deprecated HTTP legacy send API

On 6/27/2023, we started getting Post \"https://fcm.googleapis.com/fcm/send\": context deadline exceeded errors (less than 0.2% of the total) in our service that sends push-notifications to FCM.

Looking at FCM announcements, I found that the current API will be discontinued in June 2024 (I'm not sure this is related the announcement):

Firebase has announced that it will discontinue legacy Firebase Cloud Messaging (FCM) APIs starting from June 20, 2024. This decision comes as part of Firebase’s efforts to enhance security and performance. As a result, certain APIs will be deprecated in favor of the available alternatives.

https://blogiestools.com/firebase-legacy-fcm-apis-discontinued/

They have already started deprecating the API, the HTTP legacy APIs was deprecated on June 20, 2023:

Caution: Sending messages (including upstream messages) with the FCM XMPP and HTTP legacy APIs was deprecated on June 20, 2023, and will be removed in June 2024. If you are using the legacy send APIs, we strongly recommend that you migrate to the HTTP v1 API or consider using the Admin SDK to build send requests.

Migration instructions

See the migration instructions here: https://firebase.google.com/docs/cloud-messaging/migrate-v1

HTTP requests before:

POST https://fcm.googleapis.com/fcm/send

After:

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send

appleboy/go-fcm/client.go uses:

DefaultEndpoint = "https://fcm.googleapis.com/fcm/send"

Are there plans to update this Endpoint in the library?

Response error is a pointer

When the response has an error, the error message is a pointer.

2022/03/11 11:24:12 &fcm.Response{
	MulticastID:999999999999999999,
	Success:0,
	Failure:1,
	CanonicalIDs:0,
	Results:[]fcm.Result{
		fcm.Result{
			MessageID:"",
			RegistrationID:"",
			Error:(*errors.errorString)(0x14000112de0)
		}
	},
	FailedRegistrationIDs:[]string(nil),
	MessageID:0,
	Error:error(nil)
}

getting error on dependency.

google.golang.org/grpc/credentials/insecure: module google.golang.org/grpc@latest found (v0.0.0-00010101000000-000000000000, replaced by google.golang.org/[email protected]), but does not contain package google.golang.org/grpc/credentials/insecure

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.