├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── perror └── perror.go └── psdk ├── client.go ├── client_test.go ├── path.go └── types.go /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-pushdeer-sdk 2 | 3 | [pushdeer](https://github.com/easychen/pushdeer) 的golanga版本的sdk 4 | 5 | ![GitHub forks](https://img.shields.io/github/forks/Luoxin/go-pushdeer-sdk?style=social) 6 | ![GitHub Repo stars](https://img.shields.io/github/stars/Luoxin/go-pushdeer-sdk?style=social) 7 | ![GitHub](https://img.shields.io/github/license/yinguobing/cnn-facial-landmark) 8 | ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/Luoxin/go-pushdeer-sdk) 9 | 10 | ## 使用方式 11 | 12 | 在模块中安装 13 | 14 | `go get github.com/Luoxin/go-pushdeer-sdk` 15 | 16 | ### 注册设备 17 | 18 | ```go 19 | package main 20 | 21 | import ( 22 | "github.com/Luoxin/go-pushdeer-sdk/psdk" 23 | log "github.com/sirupsen/logrus" 24 | ) 25 | 26 | func main() { 27 | p, err := psdk.New("http://127.0.0.1:8800", "token") 28 | if err != nil { 29 | log.Errorf("err:%v", err) 30 | return 31 | } 32 | 33 | resp, err := p.DeviceList(&psdk.DeviceListReq{}) 34 | if err != nil { 35 | log.Errorf("err:%v", err) 36 | return 37 | } 38 | 39 | for _, device := range resp.Content.Devices { 40 | log.Infof("%+v", device) 41 | } 42 | } 43 | ``` 44 | 45 | ## TODO 46 | 47 | - [ ] 完善测试 48 | - [ ] 完善自动化检测 49 | - [ ] `/message/push` 接口中的result的处理 50 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Luoxin/go-pushdeer-sdk 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/go-resty/resty/v2 v2.7.0 7 | github.com/sirupsen/logrus v1.8.1 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= 4 | github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 8 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 9 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 10 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 11 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM= 12 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 13 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= 16 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 17 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 18 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 19 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 20 | -------------------------------------------------------------------------------- /perror/perror.go: -------------------------------------------------------------------------------- 1 | package perror 2 | 3 | import "fmt" 4 | 5 | var codeErrMap = map[int]string{ 6 | 0: "SUCCESS", 7 | 80403: "AUTH", 8 | 80501: "ARGS", 9 | 80502: "REMOTE", 10 | 80999: "UNKNOWN", 11 | } 12 | 13 | type Error struct { 14 | /* 15 | -1000 ~ -100 为 http code 的保留code,其值为 -httpCode 16 | -1 位保留code,用于默认的错误code 17 | 0 为请求成功 18 | >0 为业务保留错误 19 | */ 20 | Code int 21 | Msg string 22 | } 23 | 24 | func (e Error) Error() string { 25 | return fmt.Sprintf("code:%d,msg:%s", e.Code, e.Msg) 26 | } 27 | 28 | func CreateErr(code int, msg string) error { 29 | if code == 0 { 30 | return nil 31 | } 32 | 33 | return &Error{ 34 | Code: code, 35 | Msg: msg, 36 | } 37 | } 38 | 39 | func GenCodeErr(code int) error { 40 | if code == 0 { 41 | return nil 42 | } 43 | 44 | msg, ok := codeErrMap[code] 45 | if ok { 46 | return CreateErr(code, msg) 47 | } 48 | 49 | return CreateErr(code, "UNKNOWN") 50 | } 51 | 52 | func GetCode(err error) int { 53 | if err == nil { 54 | return 0 55 | } 56 | 57 | if x, ok := err.(*Error); ok { 58 | return x.Code 59 | } 60 | return -1 61 | } 62 | -------------------------------------------------------------------------------- /psdk/client.go: -------------------------------------------------------------------------------- 1 | package psdk 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/Luoxin/go-pushdeer-sdk/perror" 6 | "github.com/go-resty/resty/v2" 7 | log "github.com/sirupsen/logrus" 8 | "net/http" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | type PushdeerClient struct { 14 | apiBase string 15 | token string 16 | httpClient *resty.Client 17 | } 18 | 19 | func getBaseClient(apiBase string) *PushdeerClient { 20 | if strings.HasPrefix(apiBase, "http://") || strings.HasPrefix(apiBase, "https://") { 21 | 22 | } else { 23 | apiBase = "http://" + apiBase 24 | } 25 | 26 | return &PushdeerClient{ 27 | apiBase: apiBase, 28 | httpClient: resty.New(). 29 | SetTimeout(time.Minute). 30 | SetRetryWaitTime(time.Second). 31 | SetRetryCount(5). 32 | SetHeaders(map[string]string{}). 33 | SetLogger(log.New()). 34 | SetBaseURL(apiBase), 35 | } 36 | } 37 | 38 | func New(apiBase string, token string) (*PushdeerClient, error) { 39 | p := getBaseClient(apiBase) 40 | p.token = token 41 | 42 | return p, nil 43 | } 44 | 45 | // 不需要传入token,会候通过 `/login/fake` 生成一个token 46 | func NewFaker(apiBase string) (*PushdeerClient, error) { 47 | p := getBaseClient(apiBase) 48 | 49 | fakerRsp, err := p.LoginFaker() 50 | if err != nil { 51 | log.Errorf("err:%v", err) 52 | return nil, err 53 | } 54 | 55 | p.token = fakerRsp.Content.Token 56 | 57 | return p, nil 58 | } 59 | 60 | func (p *PushdeerClient) LoginFaker() (*LoginFakeRsp, error) { 61 | var rsp LoginFakeRsp 62 | resp, err := p.httpClient.R(). 63 | SetResult(&rsp). 64 | Get(LoginFake) 65 | if err != nil { 66 | log.Errorf("err:%v", err) 67 | return nil, err 68 | } 69 | 70 | err = p.checkResp(resp, &BaseRsp{ 71 | Code: rsp.Code, 72 | }) 73 | if err != nil { 74 | log.Errorf("err:%v", err) 75 | return nil, err 76 | } 77 | 78 | return &rsp, nil 79 | } 80 | 81 | func (p *PushdeerClient) UserInfo(req *UserInfoReq) (*UserInfoRsp, error) { 82 | req.Token = p.token 83 | 84 | var rsp UserInfoRsp 85 | err := p.Post(UserInfo, *req, &rsp) 86 | if err != nil { 87 | log.Errorf("err:%v", err) 88 | return nil, err 89 | } 90 | 91 | return &rsp, nil 92 | } 93 | 94 | func (p *PushdeerClient) DeviceReg(req *DeviceRegReq) (*DeviceRegRsp, error) { 95 | req.Token = p.token 96 | 97 | var rsp DeviceRegRsp 98 | resp, err := p.httpClient.R().SetResult(&rsp).Post(DeviceReg) 99 | if err != nil { 100 | log.Errorf("err:%v", err) 101 | return nil, err 102 | } 103 | 104 | err = p.checkResp(resp, rsp) 105 | if err != nil { 106 | log.Errorf("err:%v", err) 107 | return nil, err 108 | } 109 | 110 | return &rsp, nil 111 | } 112 | 113 | func (p *PushdeerClient) DeviceList(req *DeviceListReq) (*DeviceListRsp, error) { 114 | req.Token = p.token 115 | 116 | var rsp DeviceListRsp 117 | resp, err := p.httpClient.R().SetResult(&rsp).Post(DeviceList) 118 | if err != nil { 119 | log.Errorf("err:%v", err) 120 | return nil, err 121 | } 122 | 123 | err = p.checkResp(resp, rsp) 124 | if err != nil { 125 | log.Errorf("err:%v", err) 126 | return nil, err 127 | } 128 | 129 | return &rsp, nil 130 | } 131 | 132 | func (p *PushdeerClient) DeviceRemove(req *DeviceRemoveReq) (*DeviceRemoveRsp, error) { 133 | req.Token = p.token 134 | 135 | var rsp DeviceRemoveRsp 136 | resp, err := p.httpClient.R().SetResult(&rsp).Post(DeviceRemove) 137 | if err != nil { 138 | log.Errorf("err:%v", err) 139 | return nil, err 140 | } 141 | 142 | err = p.checkResp(resp, rsp) 143 | if err != nil { 144 | log.Errorf("err:%v", err) 145 | return nil, err 146 | } 147 | 148 | return &rsp, nil 149 | } 150 | 151 | func (p *PushdeerClient) KeyGen(req *KeyGenReq) (*KeyGenRsp, error) { 152 | req.Token = p.token 153 | 154 | var rsp KeyGenRsp 155 | resp, err := p.httpClient.R().SetResult(&rsp).Post(KeyGen) 156 | if err != nil { 157 | log.Errorf("err:%v", err) 158 | return nil, err 159 | } 160 | 161 | err = p.checkResp(resp, rsp) 162 | if err != nil { 163 | log.Errorf("err:%v", err) 164 | return nil, err 165 | } 166 | 167 | return &rsp, nil 168 | } 169 | 170 | func (p *PushdeerClient) KeyRegen(req *KeyRegenReq) (*KeyRegenRsp, error) { 171 | req.Token = p.token 172 | 173 | var rsp KeyRegenRsp 174 | resp, err := p.httpClient.R().SetResult(&rsp).Post(KeyRegen) 175 | if err != nil { 176 | log.Errorf("err:%v", err) 177 | return nil, err 178 | } 179 | 180 | err = p.checkResp(resp, rsp) 181 | if err != nil { 182 | log.Errorf("err:%v", err) 183 | return nil, err 184 | } 185 | 186 | return &rsp, nil 187 | } 188 | 189 | func (p *PushdeerClient) KeyList(req *KeyListReq) (*KeyListRsp, error) { 190 | req.Token = p.token 191 | var rsp KeyListRsp 192 | resp, err := p.httpClient.R().Post(KeyList) 193 | if err != nil { 194 | log.Errorf("err:%v", err) 195 | return nil, err 196 | } 197 | 198 | err = p.checkResp(resp, rsp) 199 | if err != nil { 200 | log.Errorf("err:%v", err) 201 | return nil, err 202 | } 203 | 204 | return &rsp, nil 205 | } 206 | 207 | func (p *PushdeerClient) KeyRemove(req *KeyRemoveReq) (*KeyRemoveRsp, error) { 208 | req.Token = p.token 209 | var rsp KeyRemoveRsp 210 | resp, err := p.httpClient.R().Post(KeyRemove) 211 | if err != nil { 212 | log.Errorf("err:%v", err) 213 | return nil, err 214 | } 215 | 216 | err = p.checkResp(resp, rsp) 217 | if err != nil { 218 | log.Errorf("err:%v", err) 219 | return nil, err 220 | } 221 | 222 | return &rsp, nil 223 | } 224 | 225 | func (p *PushdeerClient) MessagePush(req *MessagePushReq) (*MessagePushRsp, error) { 226 | req.Token = p.token 227 | 228 | var rsp MessagePushRsp 229 | resp, err := p.httpClient.R().Post(MessagePush) 230 | if err != nil { 231 | log.Errorf("err:%v", err) 232 | return nil, err 233 | } 234 | 235 | err = p.checkResp(resp, rsp) 236 | if err != nil { 237 | log.Errorf("err:%v", err) 238 | return nil, err 239 | } 240 | 241 | return &rsp, nil 242 | } 243 | 244 | func (p *PushdeerClient) MessageList(req *MessageListReq) (*MessageListRsp, error) { 245 | req.Token = p.token 246 | var rsp MessageListRsp 247 | resp, err := p.httpClient.R().Post(MessageList) 248 | if err != nil { 249 | log.Errorf("err:%v", err) 250 | return nil, err 251 | } 252 | 253 | err = p.checkResp(resp, rsp) 254 | if err != nil { 255 | log.Errorf("err:%v", err) 256 | return nil, err 257 | } 258 | 259 | return &rsp, nil 260 | } 261 | 262 | func (p *PushdeerClient) MessageRemove(req *MessageRemoveReq) (*MessageRemoveRsp, error) { 263 | req.Token = p.token 264 | var rsp MessageRemoveRsp 265 | resp, err := p.httpClient.R().Post(MessageRemove) 266 | if err != nil { 267 | log.Errorf("err:%v", err) 268 | return nil, err 269 | } 270 | 271 | err = p.checkResp(resp, rsp) 272 | if err != nil { 273 | log.Errorf("err:%v", err) 274 | return nil, err 275 | } 276 | 277 | return &rsp, nil 278 | } 279 | 280 | func (p *PushdeerClient) checkResp(resp *resty.Response, code Response) error { 281 | switch resp.StatusCode() { 282 | case http.StatusOK: 283 | switch code.GetCode() { 284 | case 0: 285 | return nil 286 | default: 287 | return perror.CreateErr(code.GetCode(), code.GetErrorMsg()) 288 | } 289 | default: 290 | return perror.CreateErr(-resp.StatusCode(), resp.Status()) 291 | } 292 | } 293 | 294 | func (p *PushdeerClient) Post(path string, req interface{}, rsp Response) error { 295 | buf, err := json.Marshal(req) 296 | if err != nil { 297 | log.Errorf("err:%v", err) 298 | return err 299 | } 300 | 301 | var reqForm map[string]string 302 | err = json.Unmarshal(buf, &reqForm) 303 | if err != nil { 304 | log.Errorf("err:%v", err) 305 | return err 306 | } 307 | 308 | resp, err := p.httpClient.R().SetFormData(reqForm).SetResult(rsp).Post(path) 309 | if err != nil { 310 | log.Errorf("err:%v", err) 311 | return err 312 | } 313 | 314 | err = p.checkResp(resp, rsp) 315 | if err != nil { 316 | log.Errorf("err:%v", err) 317 | return err 318 | } 319 | 320 | return nil 321 | } 322 | -------------------------------------------------------------------------------- /psdk/client_test.go: -------------------------------------------------------------------------------- 1 | package psdk 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "testing" 6 | ) 7 | 8 | const ( 9 | testAouBase = "http://127.0.0.1:8800" 10 | testToken = "" 11 | ) 12 | 13 | func getClient() (*PushdeerClient, error) { 14 | var got *PushdeerClient 15 | var err error 16 | if testToken != "" { 17 | got, err = New(testAouBase, testToken) 18 | } else { 19 | got, err = NewFaker(testAouBase) 20 | } 21 | if err != nil { 22 | log.Errorf("err:%v", err) 23 | return nil, err 24 | } 25 | 26 | log.Infof("get faker token:%v", got.token) 27 | 28 | return got, nil 29 | } 30 | 31 | func TestNewFaker(t *testing.T) { 32 | type args struct { 33 | apiBase string 34 | } 35 | tests := []struct { 36 | name string 37 | wantErr bool 38 | }{ 39 | { 40 | name: "new_faker", 41 | wantErr: false, 42 | }, 43 | } 44 | for _, tt := range tests { 45 | t.Run(tt.name, func(t *testing.T) { 46 | got, err := NewFaker(testAouBase) 47 | if (err != nil) != tt.wantErr { 48 | t.Errorf("NewFaker() error = %v, wantErr %v", err, tt.wantErr) 49 | return 50 | } 51 | if got.token == "" { 52 | t.Errorf("get token fail") 53 | } 54 | }) 55 | } 56 | } 57 | 58 | func TestUserInfo(t *testing.T) { 59 | type args struct { 60 | apiBase string 61 | } 62 | tests := []struct { 63 | name string 64 | wantErr bool 65 | }{ 66 | { 67 | name: "user_info", 68 | wantErr: false, 69 | }, 70 | } 71 | for _, tt := range tests { 72 | t.Run(tt.name, func(t *testing.T) { 73 | client, err := getClient() 74 | if err != nil { 75 | t.Errorf("err:%v", err) 76 | return 77 | } 78 | 79 | got, err := client.UserInfo(&UserInfoReq{}) 80 | if (err != nil) != tt.wantErr { 81 | t.Errorf("NewFaker() error = %v, wantErr %v", err, tt.wantErr) 82 | return 83 | } 84 | 85 | log.Infof("%+v", got) 86 | }) 87 | } 88 | } 89 | 90 | func TestDeviceReg(t *testing.T) { 91 | type args struct { 92 | apiBase string 93 | } 94 | tests := []struct { 95 | name string 96 | wantErr bool 97 | }{ 98 | { 99 | name: "device_reg", 100 | wantErr: false, 101 | }, 102 | } 103 | for _, tt := range tests { 104 | t.Run(tt.name, func(t *testing.T) { 105 | client, err := getClient() 106 | if err != nil { 107 | t.Errorf("err:%v", err) 108 | return 109 | } 110 | 111 | got, err := client.DeviceReg(&DeviceRegReq{ 112 | Name: "", 113 | DeviceId: "", 114 | IsClip: 0, 115 | }) 116 | if (err != nil) != tt.wantErr { 117 | t.Errorf("NewFaker() error = %v, wantErr %v", err, tt.wantErr) 118 | return 119 | } 120 | 121 | log.Infof("%+v", got) 122 | }) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /psdk/path.go: -------------------------------------------------------------------------------- 1 | package psdk 2 | 3 | const ( 4 | LoginFake = "/login/fake" 5 | UserInfo = "/user/info" 6 | DeviceReg = "/device/reg" 7 | DeviceList = "/device/list" 8 | DeviceRemove = "/device/remove" 9 | KeyGen = "/key/gen" 10 | KeyRegen = "/key/regen" 11 | KeyList = "/key/list" 12 | KeyRemove = "/key/remove" 13 | MessagePush = "/message/push" 14 | MessageList = "/message/list" 15 | MessageRemove = "/message/remove" 16 | ) 17 | -------------------------------------------------------------------------------- /psdk/types.go: -------------------------------------------------------------------------------- 1 | package psdk 2 | 3 | import "time" 4 | 5 | type BaseReq struct { 6 | Token string `json:"token"` 7 | } 8 | 9 | type Response interface { 10 | GetCode() int 11 | GetErrorMsg() string 12 | } 13 | 14 | type BaseRsp struct { 15 | Code int `json:"code"` 16 | Error string `json:"error"` 17 | } 18 | 19 | func (p BaseRsp) GetCode() int { 20 | return p.Code 21 | } 22 | 23 | func (p BaseRsp) GetErrorMsg() string { 24 | return p.Error 25 | } 26 | 27 | type MsgType string 28 | 29 | const ( 30 | MsgMarkdown MsgType = "markdown" 31 | MsgText MsgType = "text" 32 | MsgImage MsgType = "image" 33 | ) 34 | 35 | type LoginFakeRsp struct { 36 | Code int `json:"code"` 37 | 38 | Content struct { 39 | Token string `json:"token"` 40 | } `json:"content"` 41 | } 42 | 43 | type UserInfoReq struct { 44 | BaseReq 45 | } 46 | 47 | type UserInfoRsp struct { 48 | BaseRsp 49 | Content []struct { 50 | Id int `json:"id"` 51 | Name string `json:"name"` 52 | Email string `json:"email"` 53 | AppleId string `json:"apple_id"` 54 | WechatId interface{} `json:"wechat_id"` 55 | Level int `json:"level"` 56 | CreatedAt time.Time `json:"created_at"` 57 | UpdatedAt time.Time `json:"updated_at"` 58 | } `json:"content"` 59 | } 60 | 61 | type DeviceRegReq struct { 62 | BaseReq 63 | Name string `json:"name,omitempty"` 64 | DeviceId string `json:"device_id,omitempty"` 65 | IsClip int `json:"is_clip,omitempty"` 66 | } 67 | 68 | type DeviceRegRsp struct { 69 | BaseRsp 70 | Content struct { 71 | Devices []struct { 72 | Id int `json:"id"` 73 | Uid string `json:"uid"` 74 | Name string `json:"name"` 75 | Type string `json:"type"` 76 | DeviceId string `json:"device_id"` 77 | IsClip int `json:"is_clip"` 78 | } `json:"devices"` 79 | } `json:"content"` 80 | } 81 | 82 | type DeviceListReq struct { 83 | BaseReq 84 | } 85 | 86 | type DeviceListRsp struct { 87 | BaseRsp 88 | Content struct { 89 | Devices []struct { 90 | Id int `json:"id"` 91 | Uid string `json:"uid"` 92 | Name string `json:"name"` 93 | Type string `json:"type"` 94 | DeviceId string `json:"device_id"` 95 | IsClip int `json:"is_clip"` 96 | } `json:"devices"` 97 | } `json:"content"` 98 | } 99 | 100 | type DeviceRemoveReq struct { 101 | BaseReq 102 | Id int64 `json:"id,omitempty"` 103 | } 104 | 105 | type DeviceRemoveRsp struct { 106 | BaseRsp 107 | Content struct { 108 | Message string `json:"message"` 109 | } `json:"content"` 110 | } 111 | 112 | type KeyGenReq struct { 113 | BaseReq 114 | } 115 | 116 | type KeyGenRsp struct { 117 | BaseRsp 118 | Content struct { 119 | Keys []struct { 120 | Id int `json:"id"` 121 | Uid string `json:"uid"` 122 | Key string `json:"key"` 123 | } `json:"keys"` 124 | } `json:"content"` 125 | } 126 | 127 | type KeyRegenReq struct { 128 | BaseReq 129 | } 130 | 131 | type KeyRegenRsp struct { 132 | BaseRsp 133 | Content struct { 134 | Message string `json:"message"` 135 | } `json:"content"` 136 | } 137 | 138 | type KeyListReq struct { 139 | BaseReq 140 | Id int64 `json:"id,omitempty"` 141 | } 142 | 143 | type KeyListRsp struct { 144 | BaseRsp 145 | Content struct { 146 | Keys []struct { 147 | Id int `json:"id"` 148 | Uid string `json:"uid"` 149 | Key string `json:"key"` 150 | } `json:"keys"` 151 | } `json:"content"` 152 | } 153 | 154 | type KeyRemoveReq struct { 155 | BaseReq 156 | Id int64 `json:"id,omitempty"` 157 | } 158 | 159 | type KeyRemoveRsp struct { 160 | BaseRsp 161 | Content struct { 162 | Message string `json:"message"` 163 | } `json:"content"` 164 | } 165 | 166 | type MessagePushReq struct { 167 | BaseReq 168 | PushKey string `json:"pushkey,omitempty"` 169 | Text string `json:"text,omitempty"` 170 | Desp string `json:"desp,omitempty"` 171 | Type MsgType `json:"type,omitempty"` 172 | } 173 | 174 | type MessagePushRsp struct { 175 | BaseRsp 176 | Result []string `json:"result"` 177 | } 178 | 179 | type MessageListReq struct { 180 | BaseReq 181 | Limit uint32 `json:"limit,omitempty" validate:"max=100"` 182 | } 183 | 184 | type MessageListRsp struct { 185 | BaseRsp 186 | Content struct { 187 | Messages []struct { 188 | Id int64 `json:"id"` 189 | Uid string `json:"uid"` 190 | Text string `json:"text"` 191 | Desp string `json:"desp"` 192 | Type string `json:"type"` 193 | CreatedAt time.Time `json:"created_at"` 194 | } `json:"messages"` 195 | } `json:"content"` 196 | } 197 | 198 | type MessageRemoveReq struct { 199 | BaseReq 200 | Id int64 `json:"id,omitempty"` 201 | } 202 | 203 | type MessageRemoveRsp struct { 204 | BaseRsp 205 | Content struct { 206 | Message string `json:"message"` 207 | } `json:"content"` 208 | } 209 | --------------------------------------------------------------------------------