正在显示
19 个修改的文件
包含
508 行增加
和
72 行删除
document/terms/schemas/im.yaml
0 → 100644
1 | +version: v1 | ||
2 | +kind: Schema | ||
3 | +metadata: | ||
4 | + name: im | ||
5 | + description: 冗余附加数据 | ||
6 | + attributes: | ||
7 | + - name: accid | ||
8 | + description: 网易云信ID | ||
9 | + type: | ||
10 | + primitive: string | ||
11 | + - name: imToken | ||
12 | + description: 网易云信Token | ||
13 | + type: | ||
14 | + primitive: string | ||
15 | + - name: csAccountId | ||
16 | + description: 系统分配客服ID | ||
17 | + type: | ||
18 | + primitive: string |
@@ -14,6 +14,10 @@ metadata: | @@ -14,6 +14,10 @@ metadata: | ||
14 | description: 手机认证 | 14 | description: 手机认证 |
15 | type: | 15 | type: |
16 | schemal: phoneAuth | 16 | schemal: phoneAuth |
17 | + - name: im | ||
18 | + description: IM信息 | ||
19 | + type: | ||
20 | + schemal: im | ||
17 | - ref: createAt | 21 | - ref: createAt |
18 | required: true | 22 | required: true |
19 | - ref: updateAt | 23 | - ref: updateAt |
@@ -31,9 +31,9 @@ metadata: | @@ -31,9 +31,9 @@ metadata: | ||
31 | type: | 31 | type: |
32 | array: int64 | 32 | array: int64 |
33 | - name: collectedMenus | 33 | - name: collectedMenus |
34 | - description: 收藏的菜单(工作台) | 34 | + description: 收藏的菜单(工作台)(菜单编码列表) |
35 | type: | 35 | type: |
36 | - array: menu | 36 | + array: string |
37 | - name: cooperationInfo | 37 | - name: cooperationInfo |
38 | description: 共创信息 (共创用户有效) | 38 | description: 共创信息 (共创用户有效) |
39 | type: | 39 | type: |
pkg/domain/im.go
0 → 100644
1 | +package domainService | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + pgTransaction "github.com/linmadan/egglib-go/transaction/pg" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/domain" | ||
7 | + "gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/infrastructure/im" | ||
8 | +) | ||
9 | + | ||
10 | +type PgImService struct { | ||
11 | + transactionContext *pgTransaction.TransactionContext | ||
12 | +} | ||
13 | + | ||
14 | +func (s *PgImService) InitOrUpdateUserIMInfo(userId int64, name string) (imInfo *domain.Im, err error) { | ||
15 | + var ( | ||
16 | + //ImInfoRepository, _ = factory.CreateImInfoRepository(ctx) | ||
17 | + checkImRequest *im.CheckImRequest = &im.CheckImRequest{} | ||
18 | + IsCreated = false | ||
19 | + checkImResponse *im.CheckImResponse | ||
20 | + ) | ||
21 | + var errFind error | ||
22 | + //imInfo, errFind = ImInfoRepository.FindOne(map[string]interface{}{"user_id": userId}) | ||
23 | + // 异常 | ||
24 | + //if errFind != nil && errFind != domain.QueryNoRow { | ||
25 | + // err = errFind | ||
26 | + // return | ||
27 | + //} | ||
28 | + // 不存在 | ||
29 | + //if errFind == domain.QueryNoRow { | ||
30 | + // imInfo = &domain.Im{ | ||
31 | + // UserId: userId, | ||
32 | + // CreateTime: time.Now(), | ||
33 | + // } | ||
34 | + //} | ||
35 | + // 已存在 | ||
36 | + if errFind == nil && imInfo != nil { | ||
37 | + IsCreated = true | ||
38 | + } | ||
39 | + | ||
40 | + if len(imInfo.Accid) == 0 { | ||
41 | + //id, _ := utils.NewSnowflakeId() | ||
42 | + //imInfo.ImId = fmt.Sprintf("%v", id) | ||
43 | + } | ||
44 | + checkImRequest = &im.CheckImRequest{ | ||
45 | + UserId: userId, | ||
46 | + ImId: imInfo.Accid, | ||
47 | + Uname: name, | ||
48 | + CustomerImId: fmt.Sprintf("%v", imInfo.CsAccountId), | ||
49 | + IsCreated: IsCreated, | ||
50 | + } | ||
51 | + if checkImResponse, err = CheckIm(checkImRequest); err != nil { | ||
52 | + return | ||
53 | + } | ||
54 | + if len(imInfo.CsAccountId) == 0 { | ||
55 | + imInfo.CsAccountId = getRandomCustomerAccount(userId) | ||
56 | + } | ||
57 | + imInfo.ImToken = checkImResponse.ImToken | ||
58 | + //if _, err = ImInfoRepository.Save(imInfo); err != nil { | ||
59 | + // return | ||
60 | + //} | ||
61 | + return | ||
62 | +} | ||
63 | + | ||
64 | +// 检查ImToken | ||
65 | +func CheckIm(request *im.CheckImRequest) (rsp *im.CheckImResponse, err error) { | ||
66 | + var () | ||
67 | + rsp = &im.CheckImResponse{} | ||
68 | + if !request.IsCreated { | ||
69 | + if err = imCreate(request, rsp); err != nil { | ||
70 | + return | ||
71 | + } | ||
72 | + } else { | ||
73 | + if err = imUpdate(request, rsp); err != nil { | ||
74 | + return | ||
75 | + } | ||
76 | + } | ||
77 | + if err = imRefreshToken(request, rsp); err != nil { | ||
78 | + return | ||
79 | + } | ||
80 | + return | ||
81 | +} | ||
82 | + | ||
83 | +//create | ||
84 | +func imCreate(request *im.CheckImRequest, rsp *im.CheckImResponse) (err error) { | ||
85 | + var ( | ||
86 | + param im.UserCreate = im.UserCreate{ | ||
87 | + Accid: request.ImId, | ||
88 | + Name: request.Uname, | ||
89 | + Icon: request.Icon, | ||
90 | + } | ||
91 | + out *im.UserTokenResult | ||
92 | + ) | ||
93 | + if out, err = im.CallCreate(param); err != nil { | ||
94 | + return | ||
95 | + } | ||
96 | + if out.Code != 200 || (out.Info.Accid != request.ImId) { | ||
97 | + return im.ErrorFailCall | ||
98 | + } | ||
99 | + rsp.ImToken = out.Info.Token | ||
100 | + return | ||
101 | +} | ||
102 | + | ||
103 | +//update user info | ||
104 | +func imUpdate(request *im.CheckImRequest, rsp *im.CheckImResponse) (err error) { | ||
105 | + var ( | ||
106 | + param im.UserUpdate = im.UserUpdate{ | ||
107 | + Accid: request.ImId, | ||
108 | + Name: request.Uname, | ||
109 | + Icon: request.Icon, | ||
110 | + } | ||
111 | + out *im.BaseResp | ||
112 | + ) | ||
113 | + if out, err = im.CallUpdate(param); err != nil { | ||
114 | + return | ||
115 | + } | ||
116 | + if out.Code != 200 { | ||
117 | + return im.ErrorFailCall | ||
118 | + } | ||
119 | + return | ||
120 | +} | ||
121 | + | ||
122 | +//refresh token | ||
123 | +func imRefreshToken(request *im.CheckImRequest, rsp *im.CheckImResponse) (err error) { | ||
124 | + var ( | ||
125 | + param im.UserRefreshToken = im.UserRefreshToken{ | ||
126 | + Accid: request.ImId, | ||
127 | + } | ||
128 | + out *im.UserTokenResult | ||
129 | + ) | ||
130 | + if out, err = im.CallRefreshToken(param); err != nil { | ||
131 | + return | ||
132 | + } | ||
133 | + if out.Code != 200 || (out.Info.Accid != request.ImId) { | ||
134 | + return im.ErrorFailCall | ||
135 | + } | ||
136 | + rsp.ImToken = out.Info.Token | ||
137 | + return | ||
138 | +} | ||
139 | + | ||
140 | +// 获取客服id | ||
141 | +func getRandomCustomerAccount(userId int64) (acid string) { | ||
142 | + //ImCustomerServiceRepository, _ := factory.CreateImCustomerServiceRepository(ctx) | ||
143 | + //total, customers, err := ImCustomerServiceRepository.Find(map[string]interface{}{"sortById": domain.ASC}) | ||
144 | + //if err != nil { | ||
145 | + // log.Error(err) | ||
146 | + // return 0 | ||
147 | + //} | ||
148 | + //if total == 0 { | ||
149 | + // return 0 | ||
150 | + //} | ||
151 | + //index := userId % total | ||
152 | + //if int(index) < len(customers) { | ||
153 | + // acid, _ = strconv.ParseInt(customers[index].ImId, 10, 64) | ||
154 | + // return | ||
155 | + //} | ||
156 | + //acid, _ = strconv.ParseInt(customers[0].ImId, 10, 64) | ||
157 | + return | ||
158 | +} |
pkg/infrastructure/im/im.go
0 → 100644
1 | +package im | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | +) | ||
6 | + | ||
7 | +//func init() { | ||
8 | +// InitImClient(constant.IM_SERVICE_ADDRESS, constant.IM_APP_KEY, constant.IM_APP_SECRET) | ||
9 | +//} | ||
10 | + | ||
11 | +type RequestParam interface { | ||
12 | + Format() map[string]string | ||
13 | + GetPath() string | ||
14 | + Valid() error | ||
15 | +} | ||
16 | + | ||
17 | +//接口 | ||
18 | +func CallCreate(v UserCreate) (*UserTokenResult, error) { | ||
19 | + var result UserTokenResult | ||
20 | + btData, err := DefaultImClient.Call(v) | ||
21 | + if err != nil { | ||
22 | + return nil, err | ||
23 | + } | ||
24 | + err = json.Unmarshal(btData, &result) | ||
25 | + if err != nil { | ||
26 | + return nil, err | ||
27 | + } | ||
28 | + return &result, nil | ||
29 | +} | ||
30 | +func CallRefreshToken(v UserRefreshToken) (*UserTokenResult, error) { | ||
31 | + var result UserTokenResult | ||
32 | + btData, err := DefaultImClient.Call(v) | ||
33 | + if err != nil { | ||
34 | + return nil, err | ||
35 | + } | ||
36 | + err = json.Unmarshal(btData, &result) | ||
37 | + if err != nil { | ||
38 | + return nil, err | ||
39 | + } | ||
40 | + return &result, nil | ||
41 | +} | ||
42 | +func CallUpdate(v UserUpdate) (*BaseResp, error) { | ||
43 | + var result BaseResp | ||
44 | + btData, err := DefaultImClient.Call(v) | ||
45 | + if err != nil { | ||
46 | + return nil, err | ||
47 | + } | ||
48 | + err = json.Unmarshal(btData, &result) | ||
49 | + if err != nil { | ||
50 | + return nil, err | ||
51 | + } | ||
52 | + return &result, nil | ||
53 | +} | ||
54 | + | ||
55 | +/*CheckIm */ | ||
56 | +type CheckImRequest struct { | ||
57 | + UserId int64 | ||
58 | + ImId string | ||
59 | + Uname string | ||
60 | + Icon string | ||
61 | + CustomerImId string | ||
62 | + IsCreated bool | ||
63 | +} | ||
64 | +type CheckImResponse struct { | ||
65 | + ImToken string //net im token | ||
66 | + CsAccount int64 //客服id | ||
67 | +} |
pkg/infrastructure/im/im_test.go
0 → 100644
1 | +package im | ||
2 | + | ||
3 | +import ( | ||
4 | + "testing" | ||
5 | +) | ||
6 | + | ||
7 | +const ( | ||
8 | + IM_SERVICE_ADDRESS = "https://api.netease.im/nimserver" | ||
9 | + IM_APP_KEY = "be7c0639c10e6a69f86ce3b4fa8dc8ec" //"ebf3ae278ee1b346773b99be5080f6a9" | ||
10 | + IM_APP_SECRET = "9c5b60346613" //"67ea92e1ea45" | ||
11 | +) | ||
12 | + | ||
13 | +func TestCallCreate(t *testing.T) { | ||
14 | + InitImClient(IM_SERVICE_ADDRESS, IM_APP_KEY, IM_APP_SECRET) | ||
15 | + token, err := CallCreate(UserCreate{Accid: "1"}) | ||
16 | + if err != nil { | ||
17 | + t.Fatal(err) | ||
18 | + } | ||
19 | + if token == nil { | ||
20 | + t.Fatal("token is nil") | ||
21 | + } | ||
22 | + t.Log(token.Code, token.Info) | ||
23 | +} | ||
24 | + | ||
25 | +func TestCallRefreshToken(t *testing.T) { | ||
26 | + InitImClient(IM_SERVICE_ADDRESS, IM_APP_KEY, IM_APP_SECRET) | ||
27 | + token, err := CallRefreshToken(UserRefreshToken{Accid: "1"}) | ||
28 | + if err != nil { | ||
29 | + t.Fatal(err) | ||
30 | + } | ||
31 | + if token == nil { | ||
32 | + t.Fatal("token is nil") | ||
33 | + } | ||
34 | + t.Log(token.Code, token.Info) | ||
35 | +} | ||
36 | + | ||
37 | +func TestCallUpdate(t *testing.T) { | ||
38 | + InitImClient(IM_SERVICE_ADDRESS, IM_APP_KEY, IM_APP_SECRET) | ||
39 | + token, err := CallUpdate(UserUpdate{Accid: "1", Name: "tip tok"}) | ||
40 | + if err != nil { | ||
41 | + t.Fatal(err) | ||
42 | + } | ||
43 | + if token == nil { | ||
44 | + t.Fatal("token is nil") | ||
45 | + } | ||
46 | + t.Log(token.Code) | ||
47 | +} |
pkg/infrastructure/im/netease.go
0 → 100644
1 | +package im | ||
2 | + | ||
3 | +import ( | ||
4 | + "crypto/sha1" | ||
5 | + "encoding/hex" | ||
6 | + "fmt" | ||
7 | + "io/ioutil" | ||
8 | + "math/rand" | ||
9 | + "net/http" | ||
10 | + "net/url" | ||
11 | + "strconv" | ||
12 | + "strings" | ||
13 | + "time" | ||
14 | +) | ||
15 | + | ||
16 | +var DefaultImClient Client | ||
17 | + | ||
18 | +var ErrorFailCall = fmt.Errorf(" imclient call failed") | ||
19 | + | ||
20 | +func InitImClient(baseUrl, appKey, appSecret string) { | ||
21 | + DefaultImClient = Client{ | ||
22 | + baseUrl: baseUrl, | ||
23 | + appKey: appKey, | ||
24 | + appSecret: appSecret, | ||
25 | + } | ||
26 | +} | ||
27 | + | ||
28 | +type Client struct { | ||
29 | + baseUrl string | ||
30 | + appKey string | ||
31 | + appSecret string | ||
32 | +} | ||
33 | + | ||
34 | +func (i Client) Call(param RequestParam) ([]byte, error) { | ||
35 | + return i.httpDo(param.GetPath(), param.Format()) | ||
36 | +} | ||
37 | +func (i Client) buildHeader() http.Header { | ||
38 | + var h = http.Header{} | ||
39 | + curTime := strconv.FormatInt(time.Now().Unix(), 10) | ||
40 | + nonce := strconv.FormatInt(time.Now().Unix()+rand.Int63n(5000), 10) | ||
41 | + checkSum := buildCheckSum(i.appSecret, nonce, curTime) | ||
42 | + h.Set("Content-Type", "application/x-www-form-urlencoded") | ||
43 | + h.Set("AppKey", i.appKey) | ||
44 | + h.Set("Nonce", nonce) | ||
45 | + h.Set("CurTime", curTime) | ||
46 | + h.Set("CheckSum", checkSum) | ||
47 | + return h | ||
48 | +} | ||
49 | +func (i Client) httpDo(path string, posts map[string]string) ([]byte, error) { | ||
50 | + client := http.Client{ | ||
51 | + Timeout: 5 * time.Second, //请求超时时间5秒 | ||
52 | + } | ||
53 | + reqURL := i.baseUrl + path | ||
54 | + params := url.Values{} | ||
55 | + for k, v := range posts { | ||
56 | + params.Add(k, v) | ||
57 | + } | ||
58 | + req, err := http.NewRequest("POST", reqURL, strings.NewReader(params.Encode())) | ||
59 | + if err != nil { | ||
60 | + return nil, err | ||
61 | + } | ||
62 | + req.Header = i.buildHeader() | ||
63 | + resp, err := client.Do(req) | ||
64 | + if err != nil { | ||
65 | + return nil, err | ||
66 | + } | ||
67 | + defer resp.Body.Close() | ||
68 | + | ||
69 | + body, err := ioutil.ReadAll(resp.Body) | ||
70 | + if err != nil { | ||
71 | + return nil, err | ||
72 | + } | ||
73 | + | ||
74 | + return body, nil | ||
75 | +} | ||
76 | + | ||
77 | +func buildCheckSum(appSecret string, nonce string, curTime string) string { | ||
78 | + str := []byte(appSecret + nonce + curTime) | ||
79 | + sh := sha1.New() | ||
80 | + sh.Write(str) | ||
81 | + result := hex.EncodeToString(sh.Sum(nil)) | ||
82 | + return strings.ToLower(result) | ||
83 | +} |
pkg/infrastructure/im/netease_request.go
0 → 100644
1 | +package im | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | +) | ||
6 | + | ||
7 | +var ( | ||
8 | + _ RequestParam = UserCreate{} | ||
9 | + _ RequestParam = UserUpdate{} | ||
10 | + _ RequestParam = UserRefreshToken{} | ||
11 | +) | ||
12 | + | ||
13 | +type BaseResp struct { | ||
14 | + Code int `json:"code"` | ||
15 | +} | ||
16 | + | ||
17 | +// TokenInfo 云通信Token | ||
18 | +type TokenInfo struct { | ||
19 | + Token string `json:"token"` | ||
20 | + Accid string `json:"accid"` | ||
21 | + Name string `json:"name"` | ||
22 | +} | ||
23 | +type UserTokenResult struct { | ||
24 | + BaseResp | ||
25 | + Info TokenInfo `json:"info"` | ||
26 | +} | ||
27 | + | ||
28 | +// 创建网易云通信ID | ||
29 | +type UserCreate struct { | ||
30 | + Accid string //网易云通信ID,最大长度32字符 | ||
31 | + Name string //ID昵称,最大长度64字符。 | ||
32 | + Props string //json属性,开发者可选填,最大长度1024字符 | ||
33 | + Icon string //ID头像URL,开发者可选填,最大长度1024字符 | ||
34 | + /** | ||
35 | + 云通信ID可以指定登录token值,最大长度128字符, | ||
36 | + 并更新,如果未指定,会自动生成token,并在 | ||
37 | + 创建成功后返回 | ||
38 | + **/ | ||
39 | + Token string | ||
40 | + Sign string //签名 | ||
41 | + Email string | ||
42 | + Birth string | ||
43 | + Mobile string | ||
44 | + Gender int //0未知,1男,2女 | ||
45 | + Ex string //扩展字段 | ||
46 | +} | ||
47 | + | ||
48 | +func (p UserCreate) Format() map[string]string { | ||
49 | + return map[string]string{ | ||
50 | + "accid": p.Accid, | ||
51 | + "name": p.Name, | ||
52 | + "props": p.Props, | ||
53 | + "icon": p.Icon, | ||
54 | + "token": p.Token, | ||
55 | + "sign": p.Sign, | ||
56 | + "email": p.Email, | ||
57 | + "birth": p.Birth, | ||
58 | + "mobile": p.Mobile, | ||
59 | + "gender": fmt.Sprintf("%d", p.Gender), | ||
60 | + "ex": p.Ex, | ||
61 | + } | ||
62 | +} | ||
63 | +func (p UserCreate) GetPath() string { | ||
64 | + return "/user/create.action" | ||
65 | +} | ||
66 | +func (p UserCreate) Valid() error { | ||
67 | + return nil | ||
68 | +} | ||
69 | + | ||
70 | +// 重置网易云通信token | ||
71 | +type UserRefreshToken struct { | ||
72 | + Accid string //网易云通信ID,最大长度32字符,必须保证一个 APP内唯一 | ||
73 | +} | ||
74 | + | ||
75 | +func (p UserRefreshToken) Format() map[string]string { | ||
76 | + return map[string]string{ | ||
77 | + "accid": p.Accid, | ||
78 | + } | ||
79 | +} | ||
80 | +func (p UserRefreshToken) GetPath() string { | ||
81 | + return "/user/refreshToken.action" | ||
82 | +} | ||
83 | +func (p UserRefreshToken) Valid() error { | ||
84 | + return nil | ||
85 | +} | ||
86 | + | ||
87 | +// 更新网易云通信token | ||
88 | +type UserUpdate struct { | ||
89 | + Accid string | ||
90 | + Name string //这边网易云要有昵称以手机号码为昵称 | ||
91 | + Icon string //icon默认头像 | ||
92 | + Sign string //签名 | ||
93 | + Email string | ||
94 | + Birth string | ||
95 | + Mobile string | ||
96 | + Gender int //0未知,1男,2女 | ||
97 | + Ex string //扩展字段 | ||
98 | +} | ||
99 | + | ||
100 | +func (u UserUpdate) Format() map[string]string { | ||
101 | + return map[string]string{ | ||
102 | + "accid": u.Accid, | ||
103 | + "name": u.Name, | ||
104 | + "icon": u.Icon, | ||
105 | + "sign": u.Sign, | ||
106 | + "email": u.Email, | ||
107 | + "birth": u.Birth, | ||
108 | + "mobile": u.Mobile, | ||
109 | + "gender": fmt.Sprintf("%d", u.Gender), | ||
110 | + "ex": u.Ex, | ||
111 | + } | ||
112 | +} | ||
113 | +func (u UserUpdate) GetPath() string { | ||
114 | + return "/user/refreshToken.action" | ||
115 | +} | ||
116 | +func (u UserUpdate) Valid() error { | ||
117 | + return nil | ||
118 | +} |
-
请 注册 或 登录 后发表评论