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>
HTMLGo后端 (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
Facebook评论