{"id":18665076,"url":"https://github.com/awakari/client-sdk-go","last_synced_at":"2025-08-30T18:31:39.027Z","repository":{"id":167946550,"uuid":"642425186","full_name":"awakari/client-sdk-go","owner":"awakari","description":"Awakari Golang Client SDK library","archived":false,"fork":false,"pushed_at":"2024-11-05T11:49:33.000Z","size":222,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-05T12:53:30.719Z","etag":null,"topics":["client-library","event-driven","golang","grpc","grpc-go","real-time-search","realtime-search-engine","sdk","sdk-go","search-alerts"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/awakari.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-18T14:35:10.000Z","updated_at":"2024-11-05T11:49:21.000Z","dependencies_parsed_at":"2023-10-01T19:45:21.933Z","dependency_job_id":"efd2baf4-6496-4197-a748-be34003f0162","html_url":"https://github.com/awakari/client-sdk-go","commit_stats":null,"previous_names":["awakari/client-sdk-go"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awakari%2Fclient-sdk-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awakari%2Fclient-sdk-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awakari%2Fclient-sdk-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awakari%2Fclient-sdk-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/awakari","download_url":"https://codeload.github.com/awakari/client-sdk-go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231517641,"owners_count":18388792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-library","event-driven","golang","grpc","grpc-go","real-time-search","realtime-search-engine","sdk","sdk-go","search-alerts"],"created_at":"2024-11-07T08:26:10.145Z","updated_at":"2024-12-27T17:26:44.159Z","avatar_url":"https://github.com/awakari.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Contents\n\n1. [Overview](#1-overview)\u003cbr/\u003e\n2. [Security](#2-security)\u003cbr/\u003e\n   2.1. [Certificate Authority](#21-certificate-authority)\u003cbr/\u003e\n   2.2. [Client Key Pair](#22-client-key-pair)\u003cbr/\u003e\n   2.3. [User Identity](#23-user-identity)\u003cbr/\u003e\n3. [Usage](#3-usage)\u003cbr/\u003e\n   3.1. [Limits](#31-limits)\u003cbr/\u003e\n   3.2. [Permits](#32-permits)\u003cbr/\u003e\n   3.3. [Subscriptions](#33-subscriptions)\u003cbr/\u003e\n   3.4. [Messages](#34-messages)\u003cbr/\u003e\n4. [Contributing](#4-contributing)\u003cbr/\u003e\n   4.1. [Versioning](#41-versioning)\u003cbr/\u003e\n   4.2. [Issue Reporting](#42-issue-reporting)\u003cbr/\u003e\n   4.3. [Testing](#43-testing)\u003cbr/\u003e\n   \u0026nbsp;\u0026nbsp;\u0026nbsp;4.3.1. [Functional](#431-functional)\u003cbr/\u003e\n   \u0026nbsp;\u0026nbsp;\u0026nbsp;4.3.2. [Performance](#432-performance)\u003cbr/\u003e\n   4.4. [Releasing](#44-releasing)\u003cbr/\u003e\n\n# 1. Overview\n\nReference Awakari SDK for a Golang client.\n\n# 2. Security\n\nTo secure the Awakari public API usage, the mutual TLS encryption is used together with additional user identity.\n\n\u003e **Note**:\n\u003e\n\u003e Not available for self-hosted core system. \n\u003e Skip the [2. Security](#2-security) section entirely when using self-hosted core system.\n\n## 2.1. Certificate Authority\n\nUsed to authenticate the Awakari service by the client. A client should fetch it, for example: [demo instance CA](https://awakari.com/certs/ca-demo.awakari.cloud.crt).\n\n```go\npackage main\n\nimport (\n   \"github.com/awakari/client-sdk-go/api\"\n   \"os\"\n   ...\n)\n\nfunc main() {\n   ...\n   caCrt, err := os.ReadFile(\"ca.crt\")\n   if err != nil {\n\t   panic(err)\n   }\n   ...\n   client, err := api.\n       NewClientBuilder().\n       ...\n       CertAuthority(caCrt).\n       ...\n       Build()\n   ...\n}\n```\n\n## 2.2. Client Key Pair\n\nUsed to authenticate the Group Client. Contains a client's private key and a client's certificate. A client should \nrequest Awakari contacts to obtain it. \n\nA client's certificate is used by Awakari to extract the ***DN*** value. This value, e.g. \n`CN=my-service-using-awakari.com` is treated by Awakari as Group Client Identity.\n\n```go\npackage main\n\nimport (\n   \"github.com/awakari/client-sdk-go/api\"\n   \"os\"\n   ...\n)\n\nfunc main() {\n   ...\n   clientCrt, err := os.ReadFile(\"client.crt\")\n   if err != nil {\n      panic(err)\n   }\n   clientKey, err := os.ReadFile(\"client.key\")\n   if err != nil {\n      panic(err)\n   }\n   ...\n   client, err := api.\n      NewClientBuilder().\n      ...\n      ClientKeyPair(clientCrt, clientKey).\n      ...\n      Build()\n   ...\n}\n```\n\n## 2.3. User Identity\n\n\u003e **Note**:\n\u003e \n\u003e * Any Group Client can be used by many users.\n\u003e * Awakari doesn't verify a user identity and trusts any user id specified by the client.\n\nA client is required to specify a user id in every API call. The user authentication and authorization are the client's \nresponsibility. The good example is to integrate a 3-rd party identity provider and use the `sub` field from a JWT token \nas a user id.\n\n# 3. Usage\n\nSee the [int_test.go](int_test.go) for the complete test code example.\n\nBefore using the API, it's necessary to initialize the client. \nWhen using a hybrid deployment the initialization should be like follows:\n\n```go\npackage main\n\nimport (\n   \"github.com/awakari/client-sdk-go/api\"\n   \"os\"\n   ...\n)\n\nfunc main() {\n   ...\n   client, err := api.\n       NewClientBuilder().\n       ReaderUri(\"core-reader:50051\"). // skip this line if reader API is not used\n       SubscriptionsUri(\"core-subscriptionsproxy:50051\"). // skip this line if subscriptions API is not used\n       WriterUri(\"core-resolver:50051\"). // skip this line if writer API is not used\n       Build()\n   if err != nil {\n       panic(err)\n   }\n   defer client.Close()\n   ...\n}\n```\n\nThe initialization is a bit different for a serverless API usage:\n\n```go\npackage main\n\nimport (\n   \"github.com/awakari/client-sdk-go/api\"\n   \"os\"\n   ...\n)\n\nfunc main() {\n   ...\n   caCrt, err := os.ReadFile(\"ca.crt\")\n   if err != nil {\n\t   panic(err)\n   }\n   clientCrt, err := os.ReadFile(\"client.crt\")\n   if err != nil {\n      panic(err)\n   }\n   clientKey, err := os.ReadFile(\"client.key\")\n   if err != nil {\n      panic(err)\n   }\n   client, err := api.\n       NewClientBuilder().\n       CertAuthority(caCrt).\n       ClientKeyPair(clientCrt, clientKey).\n       ApiUri(\"demo.awakari.com:443\").\n       Build()\n   if err != nil {\n       panic(err)\n   }\n   defer client.Close()\n   ...\n}\n```\n\n## 3.1. Limits\n\n\u003e **Note**:\n\u003e\n\u003e Limits API is not available for self-hosted core system.\n\u003e Skip the [3.1. Limits](#31-limits) section entirely when using self-hosted core system.\n\nUsage limit represents the successful API call count limit. The limit is identified per:\n* group id\n* user id (optional)\n* subject\n\nThere are the group-level limits where user id is not specified. All users from the group share the group limit in this\ncase.\n\nUsage subject may be one of:\n* Subscriptions\n* Publish Events\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"time\"\n   ...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)\n   defer cancel()\n   var l usage.Limit\n   var err error\n   l, err = client.ReadUsageLimit(ctx, userId, usage.SubjectPublishEvents)\n   if err == nil {\n      if u.UserId == \"\" {\n         fmt.Printf(\"group usage publish events limit: %d\", l.Count)\n      } else {\n         fmt.Printf(\"user specific publish events limit: %d\", l.Count)\n      }\n   }\n   ...\n}\n```\n\n## 3.2. Permits\n\n\u003e **Note**:\n\u003e\n\u003e Permits API is not available for self-hosted core system.\n\u003e Skip the [3.2. Permits](#32-permits) section entirely when using self-hosted core system.\n\nUsage permits represents the current usage statistics (counters) by the subject. Similar to usage limit, the counters\nrepresent the group-level usage when the user id is empty.\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"time\"\n   ...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)\n   defer cancel()\n   var u usage.Usage\n   var err error\n   u, err = client.ReadUsage(ctx, userId, usage.SubjectSubscriptions)\n   if err == nil {\n      if u.UserId == \"\" {\n         fmt.Printf(\"group subscriptions usage: %d\", l.Count)\n      } else {\n         fmt.Printf(\"user specific subscriptions usage: %d\", l.Count)\n      }\n   }\n   ...\n}\n```\n\n## 3.3. Subscriptions\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"time\"\n   ...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Minute)\n   defer cancel()\n   \n   // Create a subscription\n   var subId string\n   var err error\n   subData := subscription.Data{\n      Description: \"my subscription\",\n\t  Enabled:     true,\n      Expires: time.Now().Add(24 * time.Hour), // optional, subscription will be treated as disabled after it expires\n      Condition: condition.NewBuilder().\n         AttributeKey(\"tags\").\n         AnyOfWords(\"SpaceX\").\n         BuildTextCondition(),\n   }\n   subId, err = client.CreateSubscription(ctx, userId, subData)\n   \n   // Update the subscription\n   upd := subscription.Data{\n      Description: \"my disabled subscription\",\n      Enabled:     false,\n      subData.Expires, // don't change\n      subData.Condition, // don't change\n   }\n   err = client.UpdateSubscription(ctx, userId, subId, upd)\n   \n   // Delete the subscription\n   err = client.DeleteSubscription(ctx, userId, subId)\n   if err != nil {\n      panic(err)\n   }\n   \n   // Search own subscription ids\n   var ids []string\n   limit := uint32(10)\n   ids, err = client.Search(ctx, userId, limit, \"\")\n   if err != nil {\n      panic(err)\n   } \n   for _, id := range ids {\n      // Read the subscription details\n      subData, err = client.Read(ctx, userId, id)\n      if err == nil {\n         panic(err)\n      }\n      fmt.Printf(\"subscription %d details: %+v\\n\", id, subData)\n   }\n   \n   ...\n}\n```\n\n## 3.4. Messages\n\n### 3.4.1. Publishing\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"github.com/cloudevents/sdk-go/binding/format/protobuf/v2/pb\"\n   \"time\"\n   ...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)\n   defer cancel()\n   var ws model.WriteStream[*pb.CloudEvent]\n   ws, err = client.OpenMessagesWriter(ctx, userId)\n   if err == nil {\n      panic(err)\n   }\n   defer ws.Close()\n   msgs := []*pb.CloudEvent{\n      {\n         Id:          uuid.NewString(),\n         Source:      \"http://arxiv.org/abs/2305.06364\",\n         SpecVersion: \"1.0\",\n         Type:        \"com.github.awakari.producer-rss\",\n         Attributes: map[string]*pb.CloudEventAttributeValue{\n            \"summary\": {\n               Attr: \u0026pb.CloudEventAttributeValue_CeString{\n                  CeString: \"\u003cp\u003eWe propose that the dark matter of our universe could be sterile neutrinos which reside within the twin sector of a mirror twin Higgs model. In our scenario, these particles are produced through a version of the Dodelson-Widrow mechanism that takes place entirely within the twin sector, yielding a dark matter candidate that is consistent with X-ray and gamma-ray line constraints. Furthermore, this scenario can naturally avoid the cosmological problems that are typically encountered in mirror twin Higgs models. In particular, if the sterile neutrinos in the Standard Model sector decay out of equilibrium, they can heat the Standard Model bath and reduce the contributions of the twin particles to $N_\\\\mathrm{eff}$. Such decays also reduce the effective temperature of the dark matter, thereby relaxing constraints from large-scale structure. The sterile neutrinos included in this model are compatible with the seesaw mechanism for generating Standard Model neutrino masses. \u003c/p\u003e \",\n               },\n            },\n            \"tags\": {\n               Attr: \u0026pb.CloudEventAttributeValue_CeString{\n                  CeString: \"neutrino dark matter cosmology higgs standard model dodelson-widrow\",\n               },\n            },\n            \"title\": {\n               Attr: \u0026pb.CloudEventAttributeValue_CeString{\n                  CeString: \"Twin Sterile Neutrino Dark Matter. (arXiv:2305.06364v1 [hep-ph])\",\n               },\n            },\n         },\n         Data: \u0026pb.CloudEvent_TextData{\n            TextData: \"\",\n         },\n      },\n   }\n   \n   var writtenCount uint32\n   var n uint32\n   for writtenCount \u003c uint32(len(msgs)) {\n      n, err = ws.WriteBatch(msgs)\n      if err != nil {\n         break\n      }\n      writtenCount += n\n   }\n   if err != nil {\n      panic(err)\n   }\n   ...\n}\n```\n\n### 3.4.2. Receiving\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"time\"\n...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   batchSize := uint32(16)\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)\n   defer cancel()\n   var r model.ReadStream[*pb.CloudEvent]\n   r, err = client.OpenMessagesReader(ctx, userId, subId, batchSize)\n   if err != nil {\n      panic(err)\n   }\n   defer r.Close()\n   var msgs []*pb.CloudEvent\n   for {\n      msgs, err = r.Read()\n      if err != nil {\n         break\n      }\n      fmt.Printf(\"subscription %s - received the next messages batch: %+v\\n\", subId, msgs)\n   }\n   if err != nil {\n      panic(err)\n   }\n   ...\n}\n```\n\n### 3.4.3. Receiving With Acknowledge\n\n```go\npackage main\n\nimport (\n   \"context\"\n   \"errors\"\n   \"fmt\"\n   \"github.com/awakari/client-sdk-go/api\"\n   \"github.com/awakari/client-sdk-go/model/usage\"\n   \"time\"\n)\n...\n)\n\nfunc main() {\n   ...\n   var client api.Client // TODO initialize client here\n   var userId string     // set this to \"sub\" field value from an authentication token, for example\n   batchSize := uint32(16)\n   ...\n   ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)\n   defer cancel()\n   var r model.ReadStream[*pb.CloudEvent]\n   r, err = client.OpenMessagesAckReader(ctx, userId, subId, batchSize)\n   if err != nil {\n      panic(err)\n   }\n   defer r.Close()\n   var msgs []*pb.CloudEvent\n   var ackCount uint32\n   for {\n      msgs, err = r.Read()\n      if err == nil {\n         fmt.Printf(\"subscription %s - received the next messages batch: %+v\\n\", subId, msgs)\n         ackCount, err = process(msgs)\n      }\n      if ackCount \u003e 0 {\n         err = errors.Join(err, r.Ack(ackCount))\n      }\n      if err != nil {\n         break\n      }\n   }\n   if err != nil {\n      panic(err)\n   }\n   ...\n}\n```\n\n# 4. Contributing\n\n## 4.1. Versioning\n\nThe library follows the [semantic versioning](http://semver.org/).\nThe single source of the version info is the git tag:\n```shell\ngit describe --tags --abbrev=0\n```\n\n## 4.2. Issue Reporting\n\nTODO\n\n## 4.3. Testing\n\n### 4.3.1. Functional\n\n```shell\nAPI_URI=api.local:443 \\\nCA_PATH=ca.crt \\\nCLIENT_CERT_PATH=test0.client0.crt \\\nCLIENT_PRIVATE_KEY_PATH=test0.client0.key \\\nmake test\n```\n\n### 4.3.2. Performance\n\nTODO\n\n## 4.4. Releasing\n\nTo release a new version (e.g. `1.2.3`) it's enough to put a git tag:\n```shell\ngit tag -v1.2.3\ngit push --tags\n```\n\nThe corresponding CI job is started to build a docker image and push it with the specified tag (+latest).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawakari%2Fclient-sdk-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fawakari%2Fclient-sdk-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawakari%2Fclient-sdk-go/lists"}