mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-04-25 02:58:26 +08:00
Merge remote-tracking branch 'origin/main' into v3.8-js-sdk-only
# Conflicts: # go.mod # go.sum # pkg/common/storage/controller/auth.go
This commit is contained in:
commit
5041942563
@ -1,62 +0,0 @@
|
|||||||
# Version logging for OpenIM
|
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_TOC -->
|
|
||||||
|
|
||||||
<!-- END MUNGE: GENERATED_TOC -->
|
|
||||||
|
|
||||||
{{ if .Versions -}}
|
|
||||||
<a name="unreleased"></a>
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
{{ if .Unreleased.CommitGroups -}}
|
|
||||||
{{ range .Unreleased.CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{ range .Versions }}
|
|
||||||
<a name="{{ .Tag.Name }}"></a>
|
|
||||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
|
|
||||||
{{ range .CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .RevertCommits -}}
|
|
||||||
### Reverts
|
|
||||||
{{ range .RevertCommits -}}
|
|
||||||
- {{ .Revert.Header }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .MergeCommits -}}
|
|
||||||
### Pull Requests
|
|
||||||
{{ range .MergeCommits -}}
|
|
||||||
- {{ .Header }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .NoteGroups -}}
|
|
||||||
{{ range .NoteGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Notes }}
|
|
||||||
{{ .Body }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .Versions }}
|
|
||||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
|
||||||
{{ range .Versions -}}
|
|
||||||
{{ if .Tag.Previous -}}
|
|
||||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
@ -1,67 +0,0 @@
|
|||||||
bin: git
|
|
||||||
style: github
|
|
||||||
template: CHANGELOG.tpl.md
|
|
||||||
info:
|
|
||||||
title: CHANGELOG
|
|
||||||
repository_url: https://github.com/openimsdk/open-im-server
|
|
||||||
options:
|
|
||||||
tag_filter_pattern: '^v'
|
|
||||||
sort: "date"
|
|
||||||
|
|
||||||
commits:
|
|
||||||
filters:
|
|
||||||
Type:
|
|
||||||
- feat
|
|
||||||
- fix
|
|
||||||
- perf
|
|
||||||
- refactor
|
|
||||||
- docs
|
|
||||||
- test
|
|
||||||
- chore
|
|
||||||
- ci
|
|
||||||
- build
|
|
||||||
sort_by: Scope
|
|
||||||
|
|
||||||
commit_groups:
|
|
||||||
group_by: Type
|
|
||||||
sort_by: Title
|
|
||||||
title_order:
|
|
||||||
- feat
|
|
||||||
- fix
|
|
||||||
- perf
|
|
||||||
- refactor
|
|
||||||
- docs
|
|
||||||
- test
|
|
||||||
- chore
|
|
||||||
- ci
|
|
||||||
- build
|
|
||||||
title_maps:
|
|
||||||
feat: Features
|
|
||||||
|
|
||||||
header:
|
|
||||||
pattern: "<regexp>"
|
|
||||||
pattern_maps:
|
|
||||||
- PropName
|
|
||||||
|
|
||||||
issues:
|
|
||||||
prefix:
|
|
||||||
- #
|
|
||||||
|
|
||||||
refs:
|
|
||||||
actions:
|
|
||||||
- Closes
|
|
||||||
- Fixes
|
|
||||||
|
|
||||||
merges:
|
|
||||||
pattern: "^Merge branch '(\\w+)'$"
|
|
||||||
pattern_maps:
|
|
||||||
- Source
|
|
||||||
|
|
||||||
reverts:
|
|
||||||
pattern: "^Revert \"([\\s\\S]*)\"$"
|
|
||||||
pattern_maps:
|
|
||||||
- Header
|
|
||||||
|
|
||||||
notes:
|
|
||||||
keywords:
|
|
||||||
- BREAKING CHANGE
|
|
@ -53,15 +53,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-cmdutils
|
- binary: openim-cmdutils
|
||||||
id: openim-cmdutils
|
id: openim-cmdutils
|
||||||
@ -71,15 +64,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-crontask
|
- binary: openim-crontask
|
||||||
id: openim-crontask
|
id: openim-crontask
|
||||||
@ -89,15 +75,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-msggateway
|
- binary: openim-msggateway
|
||||||
id: openim-msggateway
|
id: openim-msggateway
|
||||||
@ -107,15 +86,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-msgtransfer
|
- binary: openim-msgtransfer
|
||||||
id: openim-msgtransfer
|
id: openim-msgtransfer
|
||||||
@ -125,15 +97,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-push
|
- binary: openim-push
|
||||||
id: openim-push
|
id: openim-push
|
||||||
@ -143,15 +108,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-auth
|
- binary: openim-rpc-auth
|
||||||
id: openim-rpc-auth
|
id: openim-rpc-auth
|
||||||
@ -161,15 +119,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-conversation
|
- binary: openim-rpc-conversation
|
||||||
id: openim-rpc-conversation
|
id: openim-rpc-conversation
|
||||||
@ -179,15 +130,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-friend
|
- binary: openim-rpc-friend
|
||||||
id: openim-rpc-friend
|
id: openim-rpc-friend
|
||||||
@ -197,15 +141,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-group
|
- binary: openim-rpc-group
|
||||||
id: openim-rpc-group
|
id: openim-rpc-group
|
||||||
@ -215,15 +152,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-msg
|
- binary: openim-rpc-msg
|
||||||
id: openim-rpc-msg
|
id: openim-rpc-msg
|
||||||
@ -233,15 +163,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-third
|
- binary: openim-rpc-third
|
||||||
id: openim-rpc-third
|
id: openim-rpc-third
|
||||||
@ -251,15 +174,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
- binary: openim-rpc-user
|
- binary: openim-rpc-user
|
||||||
id: openim-rpc-user
|
id: openim-rpc-user
|
||||||
@ -269,15 +185,8 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- s390x
|
|
||||||
- mips64
|
|
||||||
- mips64le
|
|
||||||
- amd64
|
- amd64
|
||||||
- ppc64le
|
|
||||||
- arm64
|
- arm64
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
|
|
||||||
|
|
||||||
# TODO:Need a script, such as the init - release to help binary to find the right directory
|
# TODO:Need a script, such as the init - release to help binary to find the right directory
|
||||||
|
@ -13,4 +13,17 @@ rpcRegisterName:
|
|||||||
imAdminUserID: [ imAdmin ]
|
imAdminUserID: [ imAdmin ]
|
||||||
|
|
||||||
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
|
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
|
||||||
multiLoginPolicy: 1
|
multiLogin:
|
||||||
|
policy: 1
|
||||||
|
maxNumOneEnd: 30
|
||||||
|
customizeLoginNum:
|
||||||
|
ios: 1
|
||||||
|
android: 1
|
||||||
|
windows: 1
|
||||||
|
osx: 1
|
||||||
|
web: 1
|
||||||
|
miniWeb: 1
|
||||||
|
linux: 1
|
||||||
|
aPad: 1
|
||||||
|
iPad: 1
|
||||||
|
admin: 1
|
||||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.1
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/openimsdk/protocol v0.0.72-alpha.41
|
github.com/openimsdk/protocol v0.0.72-alpha.47
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16
|
github.com/openimsdk/tools v0.0.50-alpha.16
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.18.0
|
github.com/prometheus/client_golang v1.18.0
|
||||||
|
4
go.sum
4
go.sum
@ -319,8 +319,8 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
|
|||||||
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||||
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
|
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
|
||||||
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
|
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
|
||||||
github.com/openimsdk/protocol v0.0.72-alpha.41 h1:SMMoTc1iu+wtRqUqmIgqPJFejLgPeauOwoJ4VVG4iMQ=
|
github.com/openimsdk/protocol v0.0.72-alpha.47 h1:FGHnEwsA05GxT3vnz7YH3fbVkuoO3P71ZZgkQQ71MjA=
|
||||||
github.com/openimsdk/protocol v0.0.72-alpha.41/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
|
github.com/openimsdk/protocol v0.0.72-alpha.47/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc=
|
github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc=
|
||||||
github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
|
github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
@ -198,6 +198,13 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
|
|||||||
objectGroup.POST("/initiate_form_data", t.InitiateFormData)
|
objectGroup.POST("/initiate_form_data", t.InitiateFormData)
|
||||||
objectGroup.POST("/complete_form_data", t.CompleteFormData)
|
objectGroup.POST("/complete_form_data", t.CompleteFormData)
|
||||||
objectGroup.GET("/*name", t.ObjectRedirect)
|
objectGroup.GET("/*name", t.ObjectRedirect)
|
||||||
|
|
||||||
|
applicationGroup := r.Group("application")
|
||||||
|
applicationGroup.POST("/add_version", t.AddApplicationVersion)
|
||||||
|
applicationGroup.POST("/update_version", t.UpdateApplicationVersion)
|
||||||
|
applicationGroup.POST("/delete_version", t.DeleteApplicationVersion)
|
||||||
|
applicationGroup.POST("/latest_version", t.LatestApplicationVersion)
|
||||||
|
applicationGroup.POST("/page_versions", t.PageApplicationVersion)
|
||||||
}
|
}
|
||||||
// Message
|
// Message
|
||||||
msgGroup := r.Group("/msg")
|
msgGroup := r.Group("/msg")
|
||||||
@ -290,4 +297,6 @@ func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc {
|
|||||||
var Whitelist = []string{
|
var Whitelist = []string{
|
||||||
"/auth/get_admin_token",
|
"/auth/get_admin_token",
|
||||||
"/auth/parse_token",
|
"/auth/parse_token",
|
||||||
|
"/application/latest_version",
|
||||||
|
"/application/page_versions",
|
||||||
}
|
}
|
||||||
|
@ -170,3 +170,23 @@ func (o *ThirdApi) SearchLogs(c *gin.Context) {
|
|||||||
func (o *ThirdApi) GetPrometheus(c *gin.Context) {
|
func (o *ThirdApi) GetPrometheus(c *gin.Context) {
|
||||||
c.Redirect(http.StatusFound, o.GrafanaUrl)
|
c.Redirect(http.StatusFound, o.GrafanaUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ThirdApi) LatestApplicationVersion(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.LatestApplicationVersion, o.Client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ThirdApi) AddApplicationVersion(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.AddApplicationVersion, o.Client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ThirdApi) UpdateApplicationVersion(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.UpdateApplicationVersion, o.Client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ThirdApi) DeleteApplicationVersion(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.DeleteApplicationVersion, o.Client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ThirdApi) PageApplicationVersion(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.PageApplicationVersion, o.Client, c)
|
||||||
|
}
|
||||||
|
@ -1,17 +1,3 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package msggateway
|
package msggateway
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -212,7 +198,6 @@ func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *C
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wg := errgroup.Group{}
|
wg := errgroup.Group{}
|
||||||
wg.SetLimit(concurrentRequest)
|
wg.SetLimit(concurrentRequest)
|
||||||
|
|
||||||
@ -321,8 +306,32 @@ func (ws *WsServer) KickUserConn(client *Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
|
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
|
||||||
switch ws.msgGatewayConfig.Share.MultiLoginPolicy {
|
kickTokenFunc := func(kickClients []*Client) {
|
||||||
|
var kickTokens []string
|
||||||
|
ws.clients.DeleteClients(newClient.UserID, kickClients)
|
||||||
|
for _, c := range kickClients {
|
||||||
|
kickTokens = append(kickTokens, c.token)
|
||||||
|
err := c.KickOnlineMessage()
|
||||||
|
if err != nil {
|
||||||
|
log.ZWarn(c.ctx, "KickOnlineMessage", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx := mcontext.WithMustInfoCtx(
|
||||||
|
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
|
||||||
|
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
|
||||||
|
)
|
||||||
|
if _, err := ws.authClient.KickTokens(ctx, kickTokens); err != nil {
|
||||||
|
log.ZWarn(newClient.ctx, "kickTokens err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ws.msgGatewayConfig.Share.MultiLogin.Policy {
|
||||||
case constant.DefalutNotKick:
|
case constant.DefalutNotKick:
|
||||||
|
case constant.WebAndOther:
|
||||||
|
if constant.PlatformIDToClass(newClient.PlatformID) == constant.WebPlatformStr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
case constant.PCAndOther:
|
case constant.PCAndOther:
|
||||||
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
|
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
|
||||||
return
|
return
|
||||||
@ -347,6 +356,35 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
|
|||||||
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
|
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
|
||||||
"platformID", newClient.PlatformID)
|
"platformID", newClient.PlatformID)
|
||||||
}
|
}
|
||||||
|
case constant.PcMobileAndWeb:
|
||||||
|
clients, ok := ws.clients.GetAll(newClient.UserID)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
kickClients []*Client
|
||||||
|
)
|
||||||
|
for _, client := range clients {
|
||||||
|
if constant.PlatformIDToClass(client.PlatformID) == constant.PlatformIDToClass(newClient.PlatformID) {
|
||||||
|
kickClients = append(kickClients, client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kickTokenFunc(kickClients)
|
||||||
|
|
||||||
|
case constant.SingleTerminalLogin:
|
||||||
|
clients, ok := ws.clients.GetAll(newClient.UserID)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
kickClients []*Client
|
||||||
|
)
|
||||||
|
for _, client := range clients {
|
||||||
|
kickClients = append(kickClients, client)
|
||||||
|
}
|
||||||
|
kickTokenFunc(kickClients)
|
||||||
|
case constant.Customize:
|
||||||
|
// todo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,13 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush/options"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
||||||
|
"github.com/openimsdk/tools/log"
|
||||||
|
"github.com/openimsdk/tools/mcontext"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
geTUI = "geTui"
|
geTUI = "getui"
|
||||||
firebase = "fcm"
|
firebase = "fcm"
|
||||||
jPush = "jpush"
|
jPush = "jpush"
|
||||||
)
|
)
|
||||||
@ -38,6 +41,7 @@ type OfflinePusher interface {
|
|||||||
|
|
||||||
func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (OfflinePusher, error) {
|
func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPath string) (OfflinePusher, error) {
|
||||||
var offlinePusher OfflinePusher
|
var offlinePusher OfflinePusher
|
||||||
|
pushConf.Enable = strings.ToLower(pushConf.Enable)
|
||||||
switch pushConf.Enable {
|
switch pushConf.Enable {
|
||||||
case geTUI:
|
case geTUI:
|
||||||
offlinePusher = getui.NewClient(pushConf, cache)
|
offlinePusher = getui.NewClient(pushConf, cache)
|
||||||
@ -47,6 +51,7 @@ func NewOfflinePusher(pushConf *config.Push, cache cache.ThirdCache, fcmConfigPa
|
|||||||
offlinePusher = jpush.NewClient(pushConf)
|
offlinePusher = jpush.NewClient(pushConf)
|
||||||
default:
|
default:
|
||||||
offlinePusher = dummy.NewClient()
|
offlinePusher = dummy.NewClient()
|
||||||
|
log.ZWarn(mcontext.WithMustInfoCtx([]string{"push start", "admin", "admin", ""}), "Unknown push config", nil)
|
||||||
}
|
}
|
||||||
return offlinePusher, nil
|
return offlinePusher, nil
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,9 @@ func (o *OfflinePushConsumerHandler) handleMsg2OfflinePush(ctx context.Context,
|
|||||||
log.ZError(ctx, "offline push msg is empty", errs.New("offlinePushMsg is empty"), "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
log.ZError(ctx, "offline push msg is empty", errs.New("offlinePushMsg is empty"), "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if offlinePushMsg.MsgData.Status == constant.MsgStatusSending {
|
||||||
|
offlinePushMsg.MsgData.Status = constant.MsgStatusSendSuccess
|
||||||
|
}
|
||||||
log.ZInfo(ctx, "receive to OfflinePush MQ", "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
log.ZInfo(ctx, "receive to OfflinePush MQ", "userIDs", offlinePushMsg.UserIDs, "msg", offlinePushMsg.MsgData)
|
||||||
|
|
||||||
err := o.offlinePushMsg(ctx, offlinePushMsg.MsgData, offlinePushMsg.UserIDs)
|
err := o.offlinePushMsg(ctx, offlinePushMsg.MsgData, offlinePushMsg.UserIDs)
|
||||||
|
@ -194,6 +194,9 @@ func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConsumerHandler) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) ([]*msggateway.SingleMsgToUserResults, error) {
|
func (c *ConsumerHandler) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) ([]*msggateway.SingleMsgToUserResults, error) {
|
||||||
|
if msg != nil && msg.Status == constant.MsgStatusSending {
|
||||||
|
msg.Status = constant.MsgStatusSendSuccess
|
||||||
|
}
|
||||||
onlineUserIDs, offlineUserIDs, err := c.onlineCache.GetUsersOnline(ctx, pushToUserIDs)
|
onlineUserIDs, offlineUserIDs, err := c.onlineCache.GetUsersOnline(ctx, pushToUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -65,7 +65,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire),
|
redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire),
|
||||||
config.Share.Secret,
|
config.Share.Secret,
|
||||||
config.RpcConfig.TokenPolicy.Expire,
|
config.RpcConfig.TokenPolicy.Expire,
|
||||||
config.Share.MultiLoginPolicy,
|
config.Share.MultiLogin,
|
||||||
),
|
),
|
||||||
config: config,
|
config: config,
|
||||||
})
|
})
|
||||||
@ -230,3 +230,10 @@ func (s *authServer) InvalidateToken(ctx context.Context, req *pbauth.Invalidate
|
|||||||
}
|
}
|
||||||
return &pbauth.InvalidateTokenResp{}, nil
|
return &pbauth.InvalidateTokenResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *authServer) KickTokens(ctx context.Context, req *pbauth.KickTokensReq) (*pbauth.KickTokensResp, error) {
|
||||||
|
if err := s.authDatabase.BatchSetTokenMapByUidPid(ctx, req.Tokens); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pbauth.KickTokensResp{}, nil
|
||||||
|
}
|
||||||
|
@ -465,7 +465,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = g.notification.MemberEnterNotification(ctx, req.GroupID, req.InvitedUserIDs...); err != nil {
|
if err = g.notification.GroupApplicationAgreeMemberEnterNotification(ctx, req.GroupID, opUserID, req.InvitedUserIDs...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &pbgroup.InviteUserToGroupResp{}, nil
|
return &pbgroup.InviteUserToGroupResp{}, nil
|
||||||
@ -1180,36 +1180,53 @@ func (g *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if group.Status == constant.GroupStatusDismissed {
|
if group.Status == constant.GroupStatusDismissed {
|
||||||
return nil, servererrs.ErrDismissedAlready.Wrap()
|
return nil, servererrs.ErrDismissedAlready.Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.OldOwnerUserID == req.NewOwnerUserID {
|
if req.OldOwnerUserID == req.NewOwnerUserID {
|
||||||
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID == NewOwnerUserID")
|
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID == NewOwnerUserID")
|
||||||
}
|
}
|
||||||
|
|
||||||
members, err := g.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID})
|
members, err := g.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memberMap := datautil.SliceToMap(members, func(e *model.GroupMember) string { return e.UserID })
|
memberMap := datautil.SliceToMap(members, func(e *model.GroupMember) string { return e.UserID })
|
||||||
if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 {
|
if ids := datautil.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, datautil.Keys(memberMap)); len(ids) > 0 {
|
||||||
return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ","))
|
return nil, errs.ErrArgs.WrapMsg("user not in group " + strings.Join(ids, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
oldOwner := memberMap[req.OldOwnerUserID]
|
oldOwner := memberMap[req.OldOwnerUserID]
|
||||||
if oldOwner == nil {
|
if oldOwner == nil {
|
||||||
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID not in group " + req.NewOwnerUserID)
|
return nil, errs.ErrArgs.WrapMsg("OldOwnerUserID not in group " + req.NewOwnerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
newOwner := memberMap[req.NewOwnerUserID]
|
newOwner := memberMap[req.NewOwnerUserID]
|
||||||
if newOwner == nil {
|
if newOwner == nil {
|
||||||
return nil, errs.ErrArgs.WrapMsg("NewOwnerUser not in group " + req.NewOwnerUserID)
|
return nil, errs.ErrArgs.WrapMsg("NewOwnerUser not in group " + req.NewOwnerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
||||||
if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
|
if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("no permission transfer group owner")
|
return nil, errs.ErrNoPermission.WrapMsg("no permission transfer group owner")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if newOwner.MuteEndTime != time.Unix(0, 0) {
|
||||||
|
if _, err := g.CancelMuteGroupMember(ctx, &pbgroup.CancelMuteGroupMemberReq{
|
||||||
|
GroupID: group.GroupID,
|
||||||
|
UserID: req.NewOwnerUserID}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := g.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil {
|
if err := g.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1217,6 +1234,7 @@ func (g *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
|
|||||||
g.webhookAfterTransferGroupOwner(ctx, &g.config.WebhooksConfig.AfterTransferGroupOwner, req)
|
g.webhookAfterTransferGroupOwner(ctx, &g.config.WebhooksConfig.AfterTransferGroupOwner, req)
|
||||||
|
|
||||||
g.notification.GroupOwnerTransferredNotification(ctx, req)
|
g.notification.GroupOwnerTransferredNotification(ctx, req)
|
||||||
|
|
||||||
return &pbgroup.TransferGroupOwnerResp{}, nil
|
return &pbgroup.TransferGroupOwnerResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1425,32 +1443,38 @@ func (g *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.PopulateGroupMember(ctx, member); err != nil {
|
if err := g.PopulateGroupMember(ctx, member); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
|
||||||
opMember, err := g.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
|
opMember, err := g.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch member.RoleLevel {
|
switch member.RoleLevel {
|
||||||
case constant.GroupOwner:
|
case constant.GroupOwner:
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group owner mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group owner unmute")
|
||||||
case constant.GroupAdmin:
|
case constant.GroupAdmin:
|
||||||
if opMember.RoleLevel != constant.GroupOwner {
|
if opMember.RoleLevel != constant.GroupOwner {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group admin mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group admin unmute")
|
||||||
}
|
}
|
||||||
case constant.GroupOrdinaryUsers:
|
case constant.GroupOrdinaryUsers:
|
||||||
if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) {
|
if !(opMember.RoleLevel == constant.GroupAdmin || opMember.RoleLevel == constant.GroupOwner) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("set group ordinary users mute")
|
return nil, errs.ErrNoPermission.WrapMsg("Can not set group ordinary users unmute")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data := UpdateGroupMemberMutedTimeMap(time.Unix(0, 0))
|
data := UpdateGroupMemberMutedTimeMap(time.Unix(0, 0))
|
||||||
if err := g.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil {
|
if err := g.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID)
|
g.notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID)
|
||||||
|
|
||||||
return &pbgroup.CancelMuteGroupMemberResp{}, nil
|
return &pbgroup.CancelMuteGroupMemberResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1526,10 +1550,23 @@ func (g *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
|
|||||||
case 0:
|
case 0:
|
||||||
if !isAppManagerUid {
|
if !isAppManagerUid {
|
||||||
roleLevel := dbMembers[opUserIndex].RoleLevel
|
roleLevel := dbMembers[opUserIndex].RoleLevel
|
||||||
if roleLevel != constant.GroupOwner {
|
var (
|
||||||
|
dbSelf = &model.GroupMember{}
|
||||||
|
reqSelf *pbgroup.SetGroupMemberInfo
|
||||||
|
)
|
||||||
switch roleLevel {
|
switch roleLevel {
|
||||||
|
case constant.GroupOwner:
|
||||||
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
case constant.GroupAdmin:
|
case constant.GroupAdmin:
|
||||||
for _, member := range dbMembers {
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
}
|
||||||
if member.RoleLevel == constant.GroupOwner {
|
if member.RoleLevel == constant.GroupOwner {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("admin can not change group owner")
|
return nil, errs.ErrNoPermission.WrapMsg("admin can not change group owner")
|
||||||
}
|
}
|
||||||
@ -1539,17 +1576,36 @@ func (g *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
|
|||||||
}
|
}
|
||||||
case constant.GroupOrdinaryUsers:
|
case constant.GroupOrdinaryUsers:
|
||||||
for _, member := range dbMembers {
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
}
|
||||||
if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) {
|
if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("ordinary users can not change other role level")
|
return nil, errs.ErrNoPermission.WrapMsg("ordinary users can not change other role level")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
for _, member := range dbMembers {
|
for _, member := range dbMembers {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
dbSelf = member
|
||||||
|
}
|
||||||
if member.RoleLevel >= roleLevel {
|
if member.RoleLevel >= roleLevel {
|
||||||
return nil, errs.ErrNoPermission.WrapMsg("can not change higher role level")
|
return nil, errs.ErrNoPermission.WrapMsg("can not change higher role level")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, member := range req.Members {
|
||||||
|
if member.UserID == opUserID {
|
||||||
|
reqSelf = member
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reqSelf != nil && reqSelf.RoleLevel != nil {
|
||||||
|
if reqSelf.RoleLevel.GetValue() > dbSelf.RoleLevel {
|
||||||
|
return nil, errs.ErrNoPermission.WrapMsg("can not improve role level by self")
|
||||||
|
}
|
||||||
|
if roleLevel == constant.GroupOwner {
|
||||||
|
return nil, errs.ErrArgs.WrapMsg("group owner can not change own role level") // Prevent the absence of a group owner
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/openimsdk/tools/utils/datautil"
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
"github.com/openimsdk/tools/utils/stringutil"
|
"github.com/openimsdk/tools/utils/stringutil"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GroupApplicationReceiver
|
// GroupApplicationReceiver
|
||||||
@ -572,8 +573,51 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID ...string) error {
|
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) error {
|
||||||
return g.GroupApplicationAgreeMemberEnterNotification(ctx, groupID, "", entrantUserID...)
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
||||||
|
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||||
|
maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = g.msgRpcClient.SetUserConversationsMinSeq(ctx, &msg.SetUserConversationsMinSeqReq{
|
||||||
|
UserIDs: []string{entrantUserID},
|
||||||
|
ConversationID: conversationID,
|
||||||
|
Seq: maxSeq,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.conversationRpcClient.GroupChatFirstCreateConversation(ctx, groupID, []string{entrantUserID}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var group *sdkws.GroupInfo
|
||||||
|
group, err = g.getGroupInfo(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tips := &sdkws.MemberEnterTips{
|
||||||
|
Group: group,
|
||||||
|
EntrantUser: user,
|
||||||
|
OperationTime: time.Now().UnixMilli(),
|
||||||
|
}
|
||||||
|
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||||
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
|
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/openimsdk/tools/log"
|
"github.com/openimsdk/tools/log"
|
||||||
"github.com/openimsdk/tools/mcontext"
|
"github.com/openimsdk/tools/mcontext"
|
||||||
"github.com/openimsdk/tools/utils/datautil"
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
"github.com/openimsdk/tools/utils/stringutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (*pbmsg.SendMsgResp, error) {
|
func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (*pbmsg.SendMsgResp, error) {
|
||||||
@ -80,13 +79,17 @@ func (m *msgServer) sendMsgGroupChat(ctx context.Context, req *pbmsg.SendMsgReq)
|
|||||||
|
|
||||||
func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgData) {
|
func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgData) {
|
||||||
log.ZDebug(nctx, "setConversationAtInfo", "msg", msg)
|
log.ZDebug(nctx, "setConversationAtInfo", "msg", msg)
|
||||||
|
|
||||||
ctx := mcontext.NewCtx("@@@" + mcontext.GetOperationID(nctx))
|
ctx := mcontext.NewCtx("@@@" + mcontext.GetOperationID(nctx))
|
||||||
|
|
||||||
var atUserID []string
|
var atUserID []string
|
||||||
|
|
||||||
conversation := &pbconversation.ConversationReq{
|
conversation := &pbconversation.ConversationReq{
|
||||||
ConversationID: msgprocessor.GetConversationIDByMsg(msg),
|
ConversationID: msgprocessor.GetConversationIDByMsg(msg),
|
||||||
ConversationType: msg.SessionType,
|
ConversationType: msg.SessionType,
|
||||||
GroupID: msg.GroupID,
|
GroupID: msg.GroupID,
|
||||||
}
|
}
|
||||||
|
|
||||||
tagAll := datautil.Contain(constant.AtAllString, msg.AtUserIDList...)
|
tagAll := datautil.Contain(constant.AtAllString, msg.AtUserIDList...)
|
||||||
if tagAll {
|
if tagAll {
|
||||||
memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID)
|
memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID)
|
||||||
@ -94,25 +97,35 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
|
|||||||
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
atUserID = stringutil.DifferenceString([]string{constant.AtAllString}, msg.AtUserIDList)
|
|
||||||
|
memberUserIDList = datautil.DeleteElems(memberUserIDList, msg.SendID)
|
||||||
|
|
||||||
|
atUserID = datautil.Single([]string{constant.AtAllString}, msg.AtUserIDList)
|
||||||
|
|
||||||
if len(atUserID) == 0 { // just @everyone
|
if len(atUserID) == 0 { // just @everyone
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
|
||||||
} else { // @Everyone and @other people
|
} else { // @Everyone and @other people
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
|
||||||
|
|
||||||
err = m.Conversation.SetConversations(ctx, atUserID, conversation)
|
err = m.Conversation.SetConversations(ctx, atUserID, conversation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation)
|
log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation)
|
||||||
}
|
}
|
||||||
memberUserIDList = stringutil.DifferenceString(atUserID, memberUserIDList)
|
|
||||||
|
memberUserIDList = datautil.Single(atUserID, memberUserIDList)
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
|
||||||
|
|
||||||
err = m.Conversation.SetConversations(ctx, memberUserIDList, conversation)
|
err = m.Conversation.SetConversations(ctx, memberUserIDList, conversation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation)
|
log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe}
|
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe}
|
||||||
|
|
||||||
err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation)
|
err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation)
|
log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation)
|
||||||
|
117
internal/rpc/third/application.go
Normal file
117
internal/rpc/third/application.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package third
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
"github.com/openimsdk/protocol/third"
|
||||||
|
"github.com/openimsdk/tools/errs"
|
||||||
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsNotFound(err error) bool {
|
||||||
|
switch errs.Unwrap(err) {
|
||||||
|
case redis.Nil, mongo.ErrNoDocuments:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) db2pbApplication(val *model.Application) *third.ApplicationVersion {
|
||||||
|
return &third.ApplicationVersion{
|
||||||
|
Id: val.ID.Hex(),
|
||||||
|
Platform: val.Platform,
|
||||||
|
Version: val.Version,
|
||||||
|
Url: val.Url,
|
||||||
|
Text: val.Text,
|
||||||
|
Force: val.Force,
|
||||||
|
Latest: val.Latest,
|
||||||
|
CreateTime: val.CreateTime.UnixMilli(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) LatestApplicationVersion(ctx context.Context, req *third.LatestApplicationVersionReq) (*third.LatestApplicationVersionResp, error) {
|
||||||
|
res, err := t.applicationDatabase.LatestVersion(ctx, req.Platform)
|
||||||
|
if err == nil {
|
||||||
|
return &third.LatestApplicationVersionResp{Version: t.db2pbApplication(res)}, nil
|
||||||
|
} else if IsNotFound(err) {
|
||||||
|
return &third.LatestApplicationVersionResp{}, nil
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) AddApplicationVersion(ctx context.Context, req *third.AddApplicationVersionReq) (*third.AddApplicationVersionResp, error) {
|
||||||
|
if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
val := &model.Application{
|
||||||
|
ID: primitive.NewObjectID(),
|
||||||
|
Platform: req.Platform,
|
||||||
|
Version: req.Version,
|
||||||
|
Url: req.Url,
|
||||||
|
Text: req.Text,
|
||||||
|
Force: req.Force,
|
||||||
|
Latest: req.Latest,
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
}
|
||||||
|
if err := t.applicationDatabase.AddVersion(ctx, val); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.AddApplicationVersionResp{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) UpdateApplicationVersion(ctx context.Context, req *third.UpdateApplicationVersionReq) (*third.UpdateApplicationVersionResp, error) {
|
||||||
|
if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
oid, err := primitive.ObjectIDFromHex(req.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error())
|
||||||
|
}
|
||||||
|
update := make(map[string]any)
|
||||||
|
putUpdate(update, "platform", req.Platform)
|
||||||
|
putUpdate(update, "version", req.Version)
|
||||||
|
putUpdate(update, "url", req.Url)
|
||||||
|
putUpdate(update, "text", req.Text)
|
||||||
|
putUpdate(update, "force", req.Force)
|
||||||
|
putUpdate(update, "latest", req.Latest)
|
||||||
|
if err := t.applicationDatabase.UpdateVersion(ctx, oid, update); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.UpdateApplicationVersionResp{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) DeleteApplicationVersion(ctx context.Context, req *third.DeleteApplicationVersionReq) (*third.DeleteApplicationVersionResp, error) {
|
||||||
|
if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ids := make([]primitive.ObjectID, 0, len(req.Id))
|
||||||
|
for _, id := range req.Id {
|
||||||
|
oid, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error())
|
||||||
|
}
|
||||||
|
ids = append(ids, oid)
|
||||||
|
}
|
||||||
|
if err := t.applicationDatabase.DeleteVersion(ctx, ids); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.DeleteApplicationVersionResp{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) PageApplicationVersion(ctx context.Context, req *third.PageApplicationVersionReq) (*third.PageApplicationVersionResp, error) {
|
||||||
|
total, res, err := t.applicationDatabase.PageVersion(ctx, req.Platform, req.Pagination)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.PageApplicationVersionResp{
|
||||||
|
Total: total,
|
||||||
|
Versions: datautil.Slice(res, t.db2pbApplication),
|
||||||
|
}, nil
|
||||||
|
}
|
@ -44,6 +44,7 @@ type thirdServer struct {
|
|||||||
defaultExpire time.Duration
|
defaultExpire time.Duration
|
||||||
config *Config
|
config *Config
|
||||||
minio *minio.Minio
|
minio *minio.Minio
|
||||||
|
applicationDatabase controller.ApplicationDatabase
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -74,6 +75,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
applicationMgo, err := mgo.NewApplicationMgo(mgocli.GetDB())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Select the oss method according to the profile policy
|
// Select the oss method according to the profile policy
|
||||||
enable := config.RpcConfig.Object.Enable
|
enable := config.RpcConfig.Object.Enable
|
||||||
var (
|
var (
|
||||||
@ -104,6 +110,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
defaultExpire: time.Hour * 24 * 7,
|
defaultExpire: time.Hour * 24 * 7,
|
||||||
config: config,
|
config: config,
|
||||||
minio: minioCli,
|
minio: minioCli,
|
||||||
|
applicationDatabase: controller.NewApplicationDatabase(applicationMgo, redis.NewApplicationRedisCache(applicationMgo, rdb)),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -82,3 +82,11 @@ func checkValidObjectName(objectName string) error {
|
|||||||
func (t *thirdServer) IsManagerUserID(opUserID string) bool {
|
func (t *thirdServer) IsManagerUserID(opUserID string) bool {
|
||||||
return authverify.IsManagerUserID(opUserID, t.config.Share.IMAdminUserID)
|
return authverify.IsManagerUserID(opUserID, t.config.Share.IMAdminUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func putUpdate[T any](update map[string]any, name string, val interface{ GetValuePtr() *T }) {
|
||||||
|
ptrVal := val.GetValuePtr()
|
||||||
|
if ptrVal == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
update[name] = *ptrVal
|
||||||
|
}
|
||||||
|
@ -116,18 +116,17 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi
|
|||||||
|
|
||||||
func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesignateUsersReq) (resp *pbuser.GetDesignateUsersResp, err error) {
|
func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesignateUsersReq) (resp *pbuser.GetDesignateUsersResp, err error) {
|
||||||
resp = &pbuser.GetDesignateUsersResp{}
|
resp = &pbuser.GetDesignateUsersResp{}
|
||||||
users, err := s.db.FindWithError(ctx, req.UserIDs)
|
users, err := s.db.Find(ctx, req.UserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.UsersInfo = convert.UsersDB2Pb(users)
|
resp.UsersInfo = convert.UsersDB2Pb(users)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deprecated:
|
// deprecated:
|
||||||
|
// UpdateUserInfo
|
||||||
//UpdateUserInfo
|
|
||||||
|
|
||||||
func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) {
|
func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) {
|
||||||
resp = &pbuser.UpdateUserInfoResp{}
|
resp = &pbuser.UpdateUserInfoResp{}
|
||||||
err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config.Share.IMAdminUserID)
|
err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config.Share.IMAdminUserID)
|
||||||
|
@ -364,8 +364,26 @@ type Share struct {
|
|||||||
Secret string `mapstructure:"secret"`
|
Secret string `mapstructure:"secret"`
|
||||||
RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"`
|
RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"`
|
||||||
IMAdminUserID []string `mapstructure:"imAdminUserID"`
|
IMAdminUserID []string `mapstructure:"imAdminUserID"`
|
||||||
MultiLoginPolicy int `mapstructure:"multiLoginPolicy"`
|
MultiLogin MultiLogin `mapstructure:"multiLogin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MultiLogin struct {
|
||||||
|
Policy int `mapstructure:"policy"`
|
||||||
|
MaxNumOneEnd int `mapstructure:"maxNumOneEnd"`
|
||||||
|
CustomizeLoginNum struct {
|
||||||
|
IOS int `mapstructure:"ios"`
|
||||||
|
Android int `mapstructure:"android"`
|
||||||
|
Windows int `mapstructure:"windows"`
|
||||||
|
OSX int `mapstructure:"osx"`
|
||||||
|
Web int `mapstructure:"web"`
|
||||||
|
MiniWeb int `mapstructure:"miniWeb"`
|
||||||
|
Linux int `mapstructure:"linux"`
|
||||||
|
APad int `mapstructure:"aPad"`
|
||||||
|
IPad int `mapstructure:"iPad"`
|
||||||
|
Admin int `mapstructure:"admin"`
|
||||||
|
} `mapstructure:"customizeLoginNum"`
|
||||||
|
}
|
||||||
|
|
||||||
type RpcRegisterName struct {
|
type RpcRegisterName struct {
|
||||||
User string `mapstructure:"user"`
|
User string `mapstructure:"user"`
|
||||||
Friend string `mapstructure:"friend"`
|
Friend string `mapstructure:"friend"`
|
||||||
|
11
pkg/common/storage/cache/application.go
vendored
Normal file
11
pkg/common/storage/cache/application.go
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApplicationCache interface {
|
||||||
|
LatestVersion(ctx context.Context, platform string) (*model.Application, error)
|
||||||
|
DeleteCache(ctx context.Context, platforms []string) error
|
||||||
|
}
|
9
pkg/common/storage/cache/cachekey/application.go
vendored
Normal file
9
pkg/common/storage/cache/cachekey/application.go
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
const (
|
||||||
|
ApplicationLatestVersion = "APPLICATION_LATEST_VERSION:"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetApplicationLatestVersionKey(platform string) string {
|
||||||
|
return ApplicationLatestVersion + platform
|
||||||
|
}
|
19
pkg/common/storage/cache/cachekey/token.go
vendored
19
pkg/common/storage/cache/cachekey/token.go
vendored
@ -1,6 +1,9 @@
|
|||||||
package cachekey
|
package cachekey
|
||||||
|
|
||||||
import "github.com/openimsdk/protocol/constant"
|
import (
|
||||||
|
"github.com/openimsdk/protocol/constant"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UidPidToken = "UID_PID_TOKEN_STATUS:"
|
UidPidToken = "UID_PID_TOKEN_STATUS:"
|
||||||
@ -9,3 +12,17 @@ const (
|
|||||||
func GetTokenKey(userID string, platformID int) string {
|
func GetTokenKey(userID string, platformID int) string {
|
||||||
return UidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
|
return UidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAllPlatformTokenKey(userID string) []string {
|
||||||
|
res := make([]string, len(constant.PlatformID2Name))
|
||||||
|
for k := range constant.PlatformID2Name {
|
||||||
|
res[k-1] = GetTokenKey(userID, k)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlatformIDByTokenKey(key string) int {
|
||||||
|
splitKey := strings.Split(key, ":")
|
||||||
|
platform := splitKey[len(splitKey)-1]
|
||||||
|
return constant.PlatformNameToID(platform)
|
||||||
|
}
|
||||||
|
43
pkg/common/storage/cache/redis/application.go
vendored
Normal file
43
pkg/common/storage/cache/redis/application.go
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/dtm-labs/rockscache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
"github.com/openimsdk/tools/utils/datautil"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewApplicationRedisCache(db database.Application, rdb redis.UniversalClient) *ApplicationRedisCache {
|
||||||
|
return &ApplicationRedisCache{
|
||||||
|
db: db,
|
||||||
|
rcClient: rockscache.NewClient(rdb, *GetRocksCacheOptions()),
|
||||||
|
deleter: NewBatchDeleterRedis(rdb, GetRocksCacheOptions(), nil),
|
||||||
|
expireTime: time.Hour * 24 * 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApplicationRedisCache struct {
|
||||||
|
db database.Application
|
||||||
|
rcClient *rockscache.Client
|
||||||
|
deleter *BatchDeleterRedis
|
||||||
|
expireTime time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationRedisCache) LatestVersion(ctx context.Context, platform string) (*model.Application, error) {
|
||||||
|
return getCache(ctx, a.rcClient, cachekey.GetApplicationLatestVersionKey(platform), a.expireTime, func(ctx context.Context) (*model.Application, error) {
|
||||||
|
return a.db.LatestVersion(ctx, platform)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationRedisCache) DeleteCache(ctx context.Context, platforms []string) error {
|
||||||
|
if len(platforms) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return a.deleter.ExecDelWithKeys(ctx, datautil.Slice(platforms, func(platform string) string {
|
||||||
|
return cachekey.GetApplicationLatestVersionKey(platform)
|
||||||
|
}))
|
||||||
|
}
|
64
pkg/common/storage/cache/redis/token.go
vendored
64
pkg/common/storage/cache/redis/token.go
vendored
@ -1,17 +1,3 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package redis
|
package redis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -21,6 +7,7 @@ import (
|
|||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,6 +54,43 @@ func (c *tokenCache) GetTokensWithoutError(ctx context.Context, userID string, p
|
|||||||
return mm, nil
|
return mm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *tokenCache) GetAllTokensWithoutError(ctx context.Context, userID string) (map[int]map[string]int, error) {
|
||||||
|
var (
|
||||||
|
res = make(map[int]map[string]int)
|
||||||
|
resLock = sync.Mutex{}
|
||||||
|
)
|
||||||
|
|
||||||
|
keys := cachekey.GetAllPlatformTokenKey(userID)
|
||||||
|
if err := ProcessKeysBySlot(ctx, c.rdb, keys, func(ctx context.Context, slot int64, keys []string) error {
|
||||||
|
pipe := c.rdb.Pipeline()
|
||||||
|
mapRes := make([]*redis.MapStringStringCmd, len(keys))
|
||||||
|
for i, key := range keys {
|
||||||
|
mapRes[i] = pipe.HGetAll(ctx, key)
|
||||||
|
}
|
||||||
|
_, err := pipe.Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, m := range mapRes {
|
||||||
|
mm := make(map[string]int)
|
||||||
|
for k, v := range m.Val() {
|
||||||
|
state, err := strconv.Atoi(v)
|
||||||
|
if err != nil {
|
||||||
|
return errs.WrapMsg(err, "redis token value is not int", "value", v, "userID", userID)
|
||||||
|
}
|
||||||
|
mm[k] = state
|
||||||
|
}
|
||||||
|
resLock.Lock()
|
||||||
|
res[cachekey.GetPlatformIDByTokenKey(keys[i])] = mm
|
||||||
|
resLock.Unlock()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error {
|
func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error {
|
||||||
mm := make(map[string]any)
|
mm := make(map[string]any)
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@ -75,6 +99,18 @@ func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, pla
|
|||||||
return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), mm).Err())
|
return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), mm).Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *tokenCache) BatchSetTokenMapByUidPid(ctx context.Context, tokens map[string]map[string]int) error {
|
||||||
|
pipe := c.rdb.Pipeline()
|
||||||
|
for k, v := range tokens {
|
||||||
|
pipe.HSet(ctx, k, v)
|
||||||
|
}
|
||||||
|
_, err := pipe.Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errs.Wrap(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *tokenCache) DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error {
|
func (c *tokenCache) DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error {
|
||||||
return errs.Wrap(c.rdb.HDel(ctx, cachekey.GetTokenKey(userID, platformID), fields...).Err())
|
return errs.Wrap(c.rdb.HDel(ctx, cachekey.GetTokenKey(userID, platformID), fields...).Err())
|
||||||
}
|
}
|
||||||
|
2
pkg/common/storage/cache/token.go
vendored
2
pkg/common/storage/cache/token.go
vendored
@ -9,6 +9,8 @@ type TokenModel interface {
|
|||||||
// SetTokenFlagEx set token and flag with expire time
|
// SetTokenFlagEx set token and flag with expire time
|
||||||
SetTokenFlagEx(ctx context.Context, userID string, platformID int, token string, flag int) error
|
SetTokenFlagEx(ctx context.Context, userID string, platformID int, token string, flag int) error
|
||||||
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
|
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
|
||||||
|
GetAllTokensWithoutError(ctx context.Context, userID string) (map[int]map[string]int, error)
|
||||||
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
||||||
|
BatchSetTokenMapByUidPid(ctx context.Context, tokens map[string]map[string]int) error
|
||||||
DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error
|
DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error
|
||||||
}
|
}
|
||||||
|
69
pkg/common/storage/controller/application.go
Normal file
69
pkg/common/storage/controller/application.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
"github.com/openimsdk/tools/db/pagination"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApplicationDatabase interface {
|
||||||
|
LatestVersion(ctx context.Context, platform string) (*model.Application, error)
|
||||||
|
AddVersion(ctx context.Context, val *model.Application) error
|
||||||
|
UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error
|
||||||
|
DeleteVersion(ctx context.Context, id []primitive.ObjectID) error
|
||||||
|
PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*model.Application, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApplicationDatabase(db database.Application, cache cache.ApplicationCache) ApplicationDatabase {
|
||||||
|
return &applicationDatabase{db: db, cache: cache}
|
||||||
|
}
|
||||||
|
|
||||||
|
type applicationDatabase struct {
|
||||||
|
db database.Application
|
||||||
|
cache cache.ApplicationCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *applicationDatabase) LatestVersion(ctx context.Context, platform string) (*model.Application, error) {
|
||||||
|
return a.cache.LatestVersion(ctx, platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *applicationDatabase) AddVersion(ctx context.Context, val *model.Application) error {
|
||||||
|
if err := a.db.AddVersion(ctx, val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.cache.DeleteCache(ctx, []string{val.Platform})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *applicationDatabase) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error {
|
||||||
|
platforms, err := a.db.FindPlatform(ctx, []primitive.ObjectID{id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.db.UpdateVersion(ctx, id, update); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p, ok := update["platform"]; ok {
|
||||||
|
if val, ok := p.(string); ok {
|
||||||
|
platforms = append(platforms, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.cache.DeleteCache(ctx, platforms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *applicationDatabase) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error {
|
||||||
|
platforms, err := a.db.FindPlatform(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.db.DeleteVersion(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.cache.DeleteCache(ctx, platforms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *applicationDatabase) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*model.Application, error) {
|
||||||
|
return a.db.PageVersion(ctx, platforms, page)
|
||||||
|
}
|
@ -1,26 +1,12 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/openimsdk/tools/log"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
|
||||||
"github.com/openimsdk/protocol/constant"
|
"github.com/openimsdk/protocol/constant"
|
||||||
"github.com/openimsdk/tools/errs"
|
"github.com/openimsdk/tools/errs"
|
||||||
"github.com/openimsdk/tools/tokenverify"
|
"github.com/openimsdk/tools/tokenverify"
|
||||||
@ -32,18 +18,41 @@ type AuthDatabase interface {
|
|||||||
// Create token
|
// Create token
|
||||||
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
|
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
|
||||||
|
|
||||||
|
BatchSetTokenMapByUidPid(ctx context.Context, tokens []string) error
|
||||||
|
|
||||||
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type multiLoginConfig struct {
|
||||||
|
Policy int
|
||||||
|
MaxNumOneEnd int
|
||||||
|
CustomizeLoginNum map[int]int
|
||||||
|
}
|
||||||
|
|
||||||
type authDatabase struct {
|
type authDatabase struct {
|
||||||
cache cache.TokenModel
|
cache cache.TokenModel
|
||||||
accessSecret string
|
accessSecret string
|
||||||
accessExpire int64
|
accessExpire int64
|
||||||
multiLoginPolicy int
|
multiLogin multiLoginConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthDatabase(cache cache.TokenModel, accessSecret string, accessExpire int64, policy int) AuthDatabase {
|
func NewAuthDatabase(cache cache.TokenModel, accessSecret string, accessExpire int64, multiLogin config.MultiLogin) AuthDatabase {
|
||||||
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, multiLoginPolicy: policy}
|
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, multiLogin: multiLoginConfig{
|
||||||
|
Policy: multiLogin.Policy,
|
||||||
|
MaxNumOneEnd: multiLogin.MaxNumOneEnd,
|
||||||
|
CustomizeLoginNum: map[int]int{
|
||||||
|
constant.IOSPlatformID: multiLogin.CustomizeLoginNum.IOS,
|
||||||
|
constant.AndroidPlatformID: multiLogin.CustomizeLoginNum.Android,
|
||||||
|
constant.WindowsPlatformID: multiLogin.CustomizeLoginNum.Windows,
|
||||||
|
constant.OSXPlatformID: multiLogin.CustomizeLoginNum.OSX,
|
||||||
|
constant.WebPlatformID: multiLogin.CustomizeLoginNum.Web,
|
||||||
|
constant.MiniWebPlatformID: multiLogin.CustomizeLoginNum.MiniWeb,
|
||||||
|
constant.LinuxPlatformID: multiLogin.CustomizeLoginNum.Linux,
|
||||||
|
constant.AndroidPadPlatformID: multiLogin.CustomizeLoginNum.APad,
|
||||||
|
constant.IPadPlatformID: multiLogin.CustomizeLoginNum.IPad,
|
||||||
|
constant.AdminPlatformID: multiLogin.CustomizeLoginNum.Admin,
|
||||||
|
},
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the result is empty.
|
// If the result is empty.
|
||||||
@ -55,22 +64,38 @@ func (a *authDatabase) SetTokenMapByUidPid(ctx context.Context, userID string, p
|
|||||||
return a.cache.SetTokenMapByUidPid(ctx, userID, platformID, m)
|
return a.cache.SetTokenMapByUidPid(ctx, userID, platformID, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *authDatabase) BatchSetTokenMapByUidPid(ctx context.Context, tokens []string) error {
|
||||||
|
setMap := make(map[string]map[string]int)
|
||||||
|
for _, token := range tokens {
|
||||||
|
claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(a.accessSecret))
|
||||||
|
key := cachekey.GetTokenKey(claims.UserID, claims.PlatformID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
if v, ok := setMap[key]; ok {
|
||||||
|
v[token] = constant.KickedToken
|
||||||
|
} else {
|
||||||
|
setMap[key] = map[string]int{
|
||||||
|
token: constant.KickedToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := a.cache.BatchSetTokenMapByUidPid(ctx, setMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Create Token.
|
// Create Token.
|
||||||
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
|
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
|
||||||
// todo: get all platform token
|
tokens, err := a.cache.GetAllTokensWithoutError(ctx, userID)
|
||||||
tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
var deleteTokenKey []string
|
deleteTokenKey, kickedTokenKey, err := a.checkToken(ctx, tokens, platformID)
|
||||||
var kickedTokenKey []string
|
if err != nil {
|
||||||
for k, v := range tokens {
|
return "", err
|
||||||
t, err := tokenverify.GetClaimFromToken(k, authverify.Secret(a.accessSecret))
|
|
||||||
if err != nil || v != constant.NormalToken {
|
|
||||||
deleteTokenKey = append(deleteTokenKey, k)
|
|
||||||
} else if a.checkKickToken(ctx, platformID, t) {
|
|
||||||
kickedTokenKey = append(kickedTokenKey, k)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(deleteTokenKey) != 0 {
|
if len(deleteTokenKey) != 0 {
|
||||||
err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
|
err = a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
|
||||||
@ -78,16 +103,6 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminTokenMaxNum = 30
|
|
||||||
if platformID == constant.AdminPlatformID {
|
|
||||||
if len(kickedTokenKey) > adminTokenMaxNum {
|
|
||||||
kickedTokenKey = kickedTokenKey[:len(kickedTokenKey)-adminTokenMaxNum]
|
|
||||||
} else {
|
|
||||||
kickedTokenKey = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(kickedTokenKey) != 0 {
|
if len(kickedTokenKey) != 0 {
|
||||||
for _, k := range kickedTokenKey {
|
for _, k := range kickedTokenKey {
|
||||||
err := a.cache.SetTokenFlagEx(ctx, userID, platformID, k, constant.KickedToken)
|
err := a.cache.SetTokenFlagEx(ctx, userID, platformID, k, constant.KickedToken)
|
||||||
@ -111,22 +126,140 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI
|
|||||||
return tokenString, nil
|
return tokenString, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authDatabase) checkKickToken(ctx context.Context, platformID int, token *tokenverify.Claims) bool {
|
func (a *authDatabase) checkToken(ctx context.Context, tokens map[int]map[string]int, platformID int) ([]string, []string, error) {
|
||||||
switch a.multiLoginPolicy {
|
// todo: Move the logic for handling old data to another location.
|
||||||
|
var (
|
||||||
|
loginTokenMap = make(map[int][]string) // The length of the value of the map must be greater than 0
|
||||||
|
deleteToken = make([]string, 0)
|
||||||
|
kickToken = make([]string, 0)
|
||||||
|
adminToken = make([]string, 0)
|
||||||
|
unkickTerminal = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
for plfID, tks := range tokens {
|
||||||
|
for k, v := range tks {
|
||||||
|
_, err := tokenverify.GetClaimFromToken(k, authverify.Secret(a.accessSecret))
|
||||||
|
if err != nil || v != constant.NormalToken {
|
||||||
|
deleteToken = append(deleteToken, k)
|
||||||
|
} else {
|
||||||
|
if plfID != constant.AdminPlatformID {
|
||||||
|
loginTokenMap[plfID] = append(loginTokenMap[plfID], k)
|
||||||
|
} else {
|
||||||
|
adminToken = append(adminToken, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch a.multiLogin.Policy {
|
||||||
case constant.DefalutNotKick:
|
case constant.DefalutNotKick:
|
||||||
return false
|
for plt, ts := range loginTokenMap {
|
||||||
case constant.PCAndOther:
|
l := len(ts)
|
||||||
if constant.PlatformIDToClass(platformID) == constant.TerminalPC ||
|
if platformID == plt {
|
||||||
constant.PlatformIDToClass(token.PlatformID) == constant.TerminalPC {
|
l++
|
||||||
return false
|
}
|
||||||
|
limit := a.multiLogin.MaxNumOneEnd
|
||||||
|
if l > limit {
|
||||||
|
kickToken = append(kickToken, ts[:l-limit]...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
case constant.AllLoginButSameTermKick:
|
case constant.AllLoginButSameTermKick:
|
||||||
if platformID == token.PlatformID {
|
for plt, ts := range loginTokenMap {
|
||||||
return true
|
kickToken = append(kickToken, ts[:len(ts)-1]...)
|
||||||
|
if plt == platformID {
|
||||||
|
kickToken = append(kickToken, ts[len(ts)-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case constant.SingleTerminalLogin:
|
||||||
|
for _, ts := range loginTokenMap {
|
||||||
|
kickToken = append(kickToken, ts...)
|
||||||
|
}
|
||||||
|
case constant.WebAndOther:
|
||||||
|
unkickTerminal = constant.WebPlatformStr
|
||||||
|
fallthrough
|
||||||
|
case constant.PCAndOther:
|
||||||
|
if unkickTerminal == "" {
|
||||||
|
unkickTerminal = constant.TerminalPC
|
||||||
|
}
|
||||||
|
if constant.PlatformIDToClass(platformID) != unkickTerminal {
|
||||||
|
for plt, ts := range loginTokenMap {
|
||||||
|
if constant.PlatformIDToClass(plt) != unkickTerminal {
|
||||||
|
kickToken = append(kickToken, ts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var (
|
||||||
|
preKick []string
|
||||||
|
isReserve = true
|
||||||
|
)
|
||||||
|
for plt, ts := range loginTokenMap {
|
||||||
|
if constant.PlatformIDToClass(plt) != unkickTerminal {
|
||||||
|
// Keep a token from another end
|
||||||
|
if isReserve {
|
||||||
|
isReserve = false
|
||||||
|
kickToken = append(kickToken, ts[:len(ts)-1]...)
|
||||||
|
preKick = append(preKick, ts[len(ts)-1])
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
// Prioritize keeping Android
|
||||||
|
if plt == constant.AndroidPlatformID {
|
||||||
|
kickToken = append(kickToken, preKick...)
|
||||||
|
kickToken = append(kickToken, ts[:len(ts)-1]...)
|
||||||
|
} else {
|
||||||
|
kickToken = append(kickToken, ts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case constant.PcMobileAndWeb:
|
||||||
|
var (
|
||||||
|
reserved = make(map[string]bool)
|
||||||
|
)
|
||||||
|
|
||||||
|
for plt, ts := range loginTokenMap {
|
||||||
|
if constant.PlatformIDToClass(plt) == constant.PlatformIDToClass(platformID) {
|
||||||
|
kickToken = append(kickToken, ts...)
|
||||||
|
} else {
|
||||||
|
if !reserved[constant.PlatformIDToClass(plt)] {
|
||||||
|
reserved[constant.PlatformIDToClass(plt)] = true
|
||||||
|
kickToken = append(kickToken, ts[:len(ts)-1]...)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
kickToken = append(kickToken, ts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case constant.Customize:
|
||||||
|
if a.multiLogin.CustomizeLoginNum[platformID] <= 0 {
|
||||||
|
return nil, nil, errs.New("Do not allow login on this end").Wrap()
|
||||||
|
}
|
||||||
|
for plt, ts := range loginTokenMap {
|
||||||
|
l := len(ts)
|
||||||
|
if platformID == plt {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
// a.multiLogin.CustomizeLoginNum[platformID] must > 0
|
||||||
|
limit := min(a.multiLogin.CustomizeLoginNum[plt], a.multiLogin.MaxNumOneEnd)
|
||||||
|
if l > limit {
|
||||||
|
kickToken = append(kickToken, ts[:l-limit]...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
default:
|
default:
|
||||||
return false
|
return nil, nil, errs.New("unknown multiLogin policy").Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var adminTokenMaxNum = a.multiLogin.MaxNumOneEnd
|
||||||
|
if a.multiLogin.Policy == constant.Customize {
|
||||||
|
adminTokenMaxNum = a.multiLogin.CustomizeLoginNum[constant.AdminPlatformID]
|
||||||
|
}
|
||||||
|
l := len(adminToken)
|
||||||
|
if platformID == constant.AdminPlatformID {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
if l > adminTokenMaxNum {
|
||||||
|
kickToken = append(kickToken, adminToken[:l-adminTokenMaxNum]...)
|
||||||
|
}
|
||||||
|
return deleteToken, kickToken, nil
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,10 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
@ -194,7 +195,7 @@ func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Con
|
|||||||
return c.tx.Transaction(ctx, func(ctx context.Context) error {
|
return c.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||||
cache := c.cache.CloneConversationCache()
|
cache := c.cache.CloneConversationCache()
|
||||||
for _, conversation := range conversations {
|
for _, conversation := range conversations {
|
||||||
cache = cache.DelConversationVersionUserIDs(conversation.OwnerUserID)
|
cache = cache.DelConversationVersionUserIDs(conversation.OwnerUserID, conversation.UserID)
|
||||||
for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} {
|
for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} {
|
||||||
ownerUserID := v[0]
|
ownerUserID := v[0]
|
||||||
userID := v[1]
|
userID := v[1]
|
||||||
|
@ -2,6 +2,7 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/openimsdk/protocol/constant"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||||
@ -83,6 +84,9 @@ func (db *msgTransferDatabase) BatchInsertChat2DB(ctx context.Context, conversat
|
|||||||
IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount,
|
IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if msg.Status == constant.MsgStatusSending {
|
||||||
|
msg.Status = constant.MsgStatusSendSuccess
|
||||||
|
}
|
||||||
msgs[i] = &model.MsgDataModel{
|
msgs[i] = &model.MsgDataModel{
|
||||||
SendID: msg.SendID,
|
SendID: msg.SendID,
|
||||||
RecvID: msg.RecvID,
|
RecvID: msg.RecvID,
|
||||||
|
17
pkg/common/storage/database/application.go
Normal file
17
pkg/common/storage/database/application.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
"github.com/openimsdk/tools/db/pagination"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Application interface {
|
||||||
|
LatestVersion(ctx context.Context, platform string) (*model.Application, error)
|
||||||
|
AddVersion(ctx context.Context, val *model.Application) error
|
||||||
|
UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error
|
||||||
|
DeleteVersion(ctx context.Context, id []primitive.ObjectID) error
|
||||||
|
PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*model.Application, error)
|
||||||
|
FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error)
|
||||||
|
}
|
82
pkg/common/storage/database/mgo/application.go
Normal file
82
pkg/common/storage/database/mgo/application.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package mgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||||
|
"github.com/openimsdk/tools/db/mongoutil"
|
||||||
|
"github.com/openimsdk/tools/db/pagination"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewApplicationMgo(db *mongo.Database) (*ApplicationMgo, error) {
|
||||||
|
coll := db.Collection("application")
|
||||||
|
_, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
|
||||||
|
{
|
||||||
|
Keys: bson.D{
|
||||||
|
{Key: "platform", Value: 1},
|
||||||
|
{Key: "version", Value: 1},
|
||||||
|
},
|
||||||
|
Options: options.Index().SetUnique(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Keys: bson.D{
|
||||||
|
{Key: "latest", Value: -1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ApplicationMgo{coll: coll}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApplicationMgo struct {
|
||||||
|
coll *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) sort() any {
|
||||||
|
return bson.D{{"latest", -1}, {"_id", -1}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) LatestVersion(ctx context.Context, platform string) (*model.Application, error) {
|
||||||
|
return mongoutil.FindOne[*model.Application](ctx, a.coll, bson.M{"platform": platform}, options.FindOne().SetSort(a.sort()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) AddVersion(ctx context.Context, val *model.Application) error {
|
||||||
|
if val.ID.IsZero() {
|
||||||
|
val.ID = primitive.NewObjectID()
|
||||||
|
}
|
||||||
|
return mongoutil.InsertMany(ctx, a.coll, []*model.Application{val})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error {
|
||||||
|
if len(update) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return mongoutil.UpdateOne(ctx, a.coll, bson.M{"_id": id}, bson.M{"$set": update}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error {
|
||||||
|
if len(id) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return mongoutil.DeleteMany(ctx, a.coll, bson.M{"_id": bson.M{"$in": id}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*model.Application, error) {
|
||||||
|
filter := bson.M{}
|
||||||
|
if len(platforms) > 0 {
|
||||||
|
filter["platform"] = bson.M{"$in": platforms}
|
||||||
|
}
|
||||||
|
return mongoutil.FindPage[*model.Application](ctx, a.coll, filter, page, options.Find().SetSort(a.sort()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationMgo) FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error) {
|
||||||
|
if len(id) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return mongoutil.Find[string](ctx, a.coll, bson.M{"_id": bson.M{"$in": id}}, options.Find().SetProjection(bson.M{"_id": 0, "platform": 1}))
|
||||||
|
}
|
17
pkg/common/storage/model/application.go
Normal file
17
pkg/common/storage/model/application.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Application struct {
|
||||||
|
ID primitive.ObjectID `bson:"_id"`
|
||||||
|
Platform string `bson:"platform"`
|
||||||
|
Version string `bson:"version"`
|
||||||
|
Url string `bson:"url"`
|
||||||
|
Text string `bson:"text"`
|
||||||
|
Force bool `bson:"force"`
|
||||||
|
Latest bool `bson:"latest"`
|
||||||
|
CreateTime time.Time `bson:"create_time"`
|
||||||
|
}
|
@ -16,6 +16,7 @@ package rpccache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/localcache"
|
"github.com/openimsdk/open-im-server/v3/pkg/localcache"
|
||||||
@ -97,6 +98,7 @@ func (u *UserLocalCache) GetUsersInfo(ctx context.Context, userIDs []string) ([]
|
|||||||
user, err := u.GetUserInfo(ctx, userID)
|
user, err := u.GetUserInfo(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errs.ErrRecordNotFound.Is(err) {
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
log.ZWarn(ctx, "User info notFound", err, "userID", userID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -16,8 +16,8 @@ package rpcclient
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/openimsdk/protocol/auth"
|
"github.com/openimsdk/protocol/auth"
|
||||||
pbAuth "github.com/openimsdk/protocol/auth"
|
|
||||||
"github.com/openimsdk/tools/discovery"
|
"github.com/openimsdk/tools/discovery"
|
||||||
"github.com/openimsdk/tools/system/program"
|
"github.com/openimsdk/tools/system/program"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@ -38,8 +38,8 @@ type Auth struct {
|
|||||||
discov discovery.SvcDiscoveryRegistry
|
discov discovery.SvcDiscoveryRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) ParseToken(ctx context.Context, token string) (*pbAuth.ParseTokenResp, error) {
|
func (a *Auth) ParseToken(ctx context.Context, token string) (*auth.ParseTokenResp, error) {
|
||||||
req := pbAuth.ParseTokenReq{
|
req := auth.ParseTokenReq{
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
resp, err := a.Client.ParseToken(ctx, &req)
|
resp, err := a.Client.ParseToken(ctx, &req)
|
||||||
@ -49,8 +49,8 @@ func (a *Auth) ParseToken(ctx context.Context, token string) (*pbAuth.ParseToken
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) InvalidateToken(ctx context.Context, preservedToken, userID string, platformID int) (*pbAuth.InvalidateTokenResp, error) {
|
func (a *Auth) InvalidateToken(ctx context.Context, preservedToken, userID string, platformID int) (*auth.InvalidateTokenResp, error) {
|
||||||
req := pbAuth.InvalidateTokenReq{
|
req := auth.InvalidateTokenReq{
|
||||||
PreservedToken: preservedToken,
|
PreservedToken: preservedToken,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
PlatformID: int32(platformID),
|
PlatformID: int32(platformID),
|
||||||
@ -61,3 +61,14 @@ func (a *Auth) InvalidateToken(ctx context.Context, preservedToken, userID strin
|
|||||||
}
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Auth) KickTokens(ctx context.Context, tokens []string) (*auth.KickTokensResp, error) {
|
||||||
|
req := auth.KickTokensReq{
|
||||||
|
Tokens: tokens,
|
||||||
|
}
|
||||||
|
resp, err := a.Client.KickTokens(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user