Skip to content

Write a Redis publisher plug-in

We are going to use it to publish message to this subscriber

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main

import (
    "errors"

    "github.com/extism/go-pdk"
    "github.com/valyala/fastjson"
)

//export hostPrintln
func hostPrintln(offset uint64) uint64

func Println(text string) {
    memoryText := pdk.AllocateString(text)
    hostPrintln(memoryText.Offset())
}

//export hostGetEnv
func hostGetEnv(offset uint64) uint64

func GetEnv(name string) string {
    // copy the name of the environment variable to the shared memory
    variableName := pdk.AllocateString(name)
    // call the host function
    offset := hostGetEnv(variableName.Offset())

    // read the value of the result from the shared memory
    variableValue := pdk.FindMemory(offset)
    buffer := make([]byte, variableValue.Length())
    variableValue.Load(buffer)

    // cast the buffer to string and return the value
    envVarValue := string(buffer)
    return envVarValue
}

var parser = fastjson.Parser{}

//export hostInitRedisClient
func hostInitRedisClient(offset uint64) uint64

func InitRedisClient(redisClientId string, redisUri string) (string, error) {

    // Prepare the arguments for the host function
    // with a JSON string:
    // {
    //    "id": "id of the redis client",
    //    "uri": "redis uri"
    // }
    jsonStrArguments := `{"id":"` + redisClientId + `","uri":"` + redisUri + `"}`

    // Copy the string value to the shared memory
    arguments := pdk.AllocateString(jsonStrArguments)

    // Call the host function with Json string argument
    offset := hostInitRedisClient(arguments.Offset())

    // Get result from the shared memory
    // The host function (hostInitRedisClient) returns a JSON buffer:
    // {
    //   "success": "the redis client id",
    //   "failure": "error message if error, else empty"
    // }
    memoryResult := pdk.FindMemory(offset)
    buffer := make([]byte, memoryResult.Length())
    memoryResult.Load(buffer)

    JSONData, err := parser.ParseBytes(buffer)
    if err != nil {
        return "", err
    }
    if len(JSONData.GetStringBytes("failure")) == 0 {
        return string(JSONData.GetStringBytes("success")), nil
    } else {
        return "", errors.New(string(JSONData.GetStringBytes("failure")))
    }

}

//export hostRedisPublish
func hostRedisPublish(offset uint64) uint64

func RedisPublish(redisClientId string, channel string, payload string) (string, error) {
    // Prepare the arguments for the host function
    // with a JSON string:
    // {
    //    "id": "id of the redis client",
    //    "channel": "name",
    //    "payload": "Bob Morane"
    // }
    jsonStr := `{"id":"` + redisClientId + `","channel":"` + channel + `","payload":"` + payload + `"}`

    // Copy the string value to the shared memory
    arguments := pdk.AllocateString(jsonStr)

    // Call host function with the offset of the arguments
    offset := hostRedisPublish(arguments.Offset())

    // Get result from the shared memory
    // The host function (hostMemorySet) returns a JSON buffer:
    // {
    //   "success": "the value associated to the key",
    //   "failure": "error message if error, else empty"
    // }
    memoryResult := pdk.FindMemory(offset)
    buffResult := make([]byte, memoryResult.Length())
    memoryResult.Load(buffResult)

    JSONData, err := parser.ParseBytes(buffResult)

    if err != nil {
        return "", err
    }
    if len(JSONData.GetStringBytes("failure")) == 0 {
        return string(JSONData.GetStringBytes("success")), nil
    } else {
        return "", errors.New(string(JSONData.GetStringBytes("failure")))
    }
}

//export publish
func publish() uint64 {
    input := pdk.Input()

    redisURI := GetEnv("REDIS_URI")
    idRedisClient, errInit := InitRedisClient("pubsubcli", redisURI)
    if errInit != nil {
        Println("๐Ÿ˜ก " + errInit.Error())
    } else {
        Println("๐Ÿ™‚ " + idRedisClient)
    }

    RedisPublish("pubsubcli", "news", string(input))

    return 0
}

func main() {}

Build

1
2
3
4
#!/bin/bash
tinygo build -scheduler=none --no-debug \
    -o redispub.wasm \
    -target wasi main.go

Run the plug-in to publish a message

1
2
3
4
#!/bin/bash
REDIS_URI=${REDIS_URI} ./slingshot run --wasm=./redispub.wasm \
--handler=publish \
--input="I ๐Ÿ’œ Wasm โœจ"

On the subscriber side, you shoul read:

1
๐Ÿ‘‹ message: news I ๐Ÿ’œ Wasm โœจ