Skip to content

Commit

Permalink
refactor: Extract a Zulip client package (#69)
Browse files Browse the repository at this point in the history
There are two major components to this library: the Client and the Webhook.

The Client consolidates all of the code related to sending Zulip an HTTP
request. Most of it is mechanical refactoring, but I added a bit where we store
the error response if we get one.

Interesting parts of the Client:

- Credentials are loaded for each outbound request. I don't think our
  credentials change often, but hot-swapping these saved us once already!

- This reads an environment variable to see whether we're in production. I
  think that check should be moved out to app logic, but that means adding it
  everywhere this gets called. I'll do that in a future change so it's easier
  to test.

The Webhook is mostly struct definitions to match the [Zulip documentation].

The weird part of the Webhook is that `display_recipient` is  a string when it
comes from a public stream message and an array-of-users when it comes from a
DM.

[Zulip documentation]: https://zulip.com/api/outgoing-webhooks
  • Loading branch information
jdkaplan authored Sep 4, 2024
1 parent d9d7f5a commit e11bbad
Show file tree
Hide file tree
Showing 11 changed files with 731 additions and 317 deletions.
248 changes: 0 additions & 248 deletions client.go

This file was deleted.

38 changes: 28 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package main

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"

"cloud.google.com/go/firestore"
"github.com/thwidge/pairing-bot/zulip"
)

// It's alive! The application starts here.
Expand Down Expand Up @@ -60,27 +62,43 @@ func main() {
client: db,
}

ur := &zulipUserRequest{}
zulipCredentials := func(ctx context.Context) (zulip.Credentials, error) {
res, err := db.Collection("apiauth").Doc("key").Get(ctx)
if err != nil {
return zulip.Credentials{}, err
}

data := res.Data()

value, ok := data["value"]
if !ok {
return zulip.Credentials{}, errors.New(`missing key in /apiauth/key: "value"`)
}

un := &zulipUserNotification{
botUsername: botUsername,
zulipAPIURL: "https://recurse.zulipchat.com/api/v1/messages",
password, ok := value.(string)
if !ok {
return zulip.Credentials{}, fmt.Errorf(`type mismatch in /apiauth/key: expected "value" to be string, got %T`, value)
}

return zulip.Credentials{
Username: botUsername,
Password: password,
}, nil
}

sm := &zulipStreamMessage{
botUsername: botUsername,
zulipAPIURL: "https://recurse.zulipchat.com/api/v1/messages",
zulipClient, err := zulip.NewClient(zulipCredentials)
if err != nil {
panic(err)
}

pl := &PairingLogic{
rdb: rdb,
adb: adb,
pdb: pdb,
ur: ur,
un: un,
sm: sm,
rcapi: rcapi,
revdb: revdb,

zulip: zulipClient,
}

http.HandleFunc("/", http.NotFound) // will this handle anything that's not defined?
Expand Down
Loading

0 comments on commit e11bbad

Please sign in to comment.