Kubernetes部署Soketi

这是docker compose的sample

version: "3.3"
services:
  soketi:
    image: quay.io/soketi/soketi:1.4-16-debian
    restart: always
    container_name: soketi
    environment:
      - SOKETI_DEFAULT_APP_ID=saas
      - SOKETI_DEFAULT_APP_KEY=saas
      - SOKETI_DEFAULT_APP_SECRET=saas
      - SOKETI_DEBUG=0
      - SOKETI_SSL_CERT=/ssl/fullchain.pem # 配置证书
      - SOKETI_SSL_KEY=/ssl/privkey.pem # 配置证书
    ports:
      - 6001:6001
      - 9601:9601
    volumes:
      - /www/server/panel/vhost/cert/saas.xxx.com:/ssl # 共享宿主机上的ssl目录

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: soketi
  labels:
    app: soketi
spec:
  replicas: 1
  selector:
    matchLabels:
      app: soketi
  template:
    metadata:
      labels:
        app: soketi
    spec:
      containers:
        - name: soketi
          image: quay.io/soketi/soketi:1.4-16-debian
          ports:
            - containerPort: 6001
            - containerPort: 9601
          env:
            - name: SOKETI_DEFAULT_APP_ID
              value: "1443971"
            - name: SOKETI_DEFAULT_APP_KEY
              value: "18e5f87e1570f089fa86"
            - name: SOKETI_DEFAULT_APP_SECRET
              value: "b7e5e41be1b39b10c720"
            - name: SOKETI_DEBUG
              value: "1"
          restartPolicy: Always

Web前端

HTML
<!DOCTYPE html>
<html>
<head>
    <title>Pusher Demo</title>
    <script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
</head>
<body>
<h1>Pusher Test</h1>
<div id="messages"></div>

<script>
    // 替换为你的 Pusher app key 和 cluster
    //18e5f87e1570f089fa86
    const pusher = new Pusher('18e5f87e1570f089fa86', {


        cluster: 'mt1',
        wsHost: 'localhost',
        wsPort: 6001,
        wssPort: 6001,
        forceTLS: false,
        disableStats: true,
        enabledTransports: ['ws', 'wss'],

        // cluster: 'ap1',
        // encrypted: true,
        authorizer: (channel, options) => {
            return {
                authorize: (socketId, callback) => {
                    fetch('http://127.0.0.1:8100/test', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({
                            socket_id:    socketId,
                            channel_name: channel.name,
                            key:          'bar'
                        }),
                    })
                        .then(res => {
                            if (!res.ok) throw new Error(`Auth HTTP ${res.status}`);
                            return res.json();
                        })
                        .then(resp => {
                            console.log(resp);
                            console.log(resp.code);
                            console.log(resp.error);
                            console.log(resp.data);
                            if (resp.code !== 200) {
                                // 后端业务错误也可以这样反馈给 Pusher
                                callback(new Error(`Auth error: ${resp.error || 'unknown'}`), null);
                            } else {
                                // 注意:Pusher 只看 { auth: "..."},其余字段会被忽略
                                callback(null, resp.data);
                            }
                        })
                        .catch(err => {
                            callback(err, null);
                        });
                }
            };
        }
    });

    // 订阅频道
    const channel = pusher.subscribe('presence-my-channel');

    pusher.connection.bind('connected', () => {
        console.log('success');
    });

    channel.bind('pusher:subscription_succeeded', members => {
        console.log('✅ presence 订阅成功,当前成员:', members);
    });
    channel.bind('pusher:subscription_error', err => {
        console.error('❌ presence 订阅失败:', err);
    });

    // 监听事件
    channel.bind('my-event', function(data) {
        console.log(data);
        const msg = document.createElement('p');
        msg.innerText = '收到消息: ' + JSON.stringify(data);
        document.getElementById('messages').appendChild(msg);
    });
</script>
</body>
</html>
HTML

Go后端 (GoFrame)

Go

type AuthResponse struct {
	Auth        string `json:"auth"`
	ChannelData string `json:"channel_data"`
}

type ResponseJson struct {
	Code  int         `json:"code"`
	Error string      `json:"error"`
	Data  interface{} `json:"data"`
}

func AuthWithManualBody(r *ghttp.Request) {
	// 假设你从上下文、JWT 或其他地方拿到用户想订阅的频道
	socketID := r.GetForm("socket_id").String()
	channelName := r.GetForm("channel_name").String()

	// 1. 自行构造一个 map 或 struct,然后 Marshal 成 JSON
	form := url.Values{}
	form.Set("socket_id", socketID)
	form.Set("channel_name", channelName)
	params := []byte(form.Encode())

	// 2. 初始化 Pusher 客户端
	client := pusher.Client{
		AppID:   "1443971", // 与 Docker Compose 中保持一致
		Key:     "18e5f87e1570f089fa86",
		Secret:  "b7e5e41be1b39b10c720",
		Host:    "127.0.0.1:6001", // Docker 主机地址,容器内可以用 redis 可以访问,一般是 localhost
		Secure:  false,            // 非 TLS 模式
		Cluster: "mt1",            // 设置 Host 后 Cluster 会被忽略
	}

	presenceData := pusher.MemberData{
		UserID: "user-123", // dynamic user ID
		UserInfo: map[string]string{
			"name": "John Doe",
		},
	}

	// 3. 把自己构造的 rawBody 传给 AuthorizePrivateChannel
	authJSONBytes, err := client.AuthorizePresenceChannel(params, presenceData)
	if err != nil {
		r.Response.WriteStatusExit(http.StatusOK, "pusher auth error: "+err.Error())
	}

	fmt.Println(gjson.MustEncodeString(authJSONBytes))

	//4. 把pusher sdk返回的 auth bytes 装换成 struct
	authResponse := AuthResponse{}
	err1 := json.Unmarshal(authJSONBytes, &authResponse)
	if err1 != nil {
		log.Fatalf("JSON 解码失败: %v", err)
	}

	//5. 准备好需要返回的api数据结构
	result := ResponseJson{
		Code:  200,
		Error: "",
		Data: g.Map{
			"auth":         authResponse.Auth,
			"channel_data": authResponse.ChannelData,
		},
	}

	//6. 把struct装换成bytes
	resultByte, _ := gjson.Encode(result)

	// 4. API 返回
	r.Response.Header().Set("Content-Type", "application/json")
	r.Response.Write(resultByte)
}
Go

Loading

Facebook评论