├── .gitignore ├── LICENSE ├── README.md ├── SCTestServer └── scserver ├── commands.txt ├── go.mod ├── go.sum ├── main.go ├── scclient ├── client.go ├── event_listener.go ├── jsclient.go ├── models │ ├── event.go │ └── handshake.go ├── parser │ ├── messageT.go │ ├── messagetype_string.go │ └── parser.go └── utils │ ├── client_utils.go │ ├── counter.go │ └── miscellaneous.go └── tests ├── client_utils_test.go ├── counter_test.go ├── miscellaneous_test.go └── parser_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | # ignore build under build directory 17 | build/ 18 | bin/ 19 | 20 | #ignore any IDE based files 21 | .idea/** 22 | vendor/ 23 | SCTestServer/sc-testserver -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2017 Sachin Shinde 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # socketcluster-client-go 2 | Refer examples for more details : 3 | 4 | Overview 5 | -------- 6 | This client provides following functionality 7 | 8 | - Easy to setup and use 9 | - Support for emitting and listening to remote events 10 | - Pub/sub 11 | - Authentication (JWT) 12 | - Can be used for testing of all server side functions 13 | 14 | To install use 15 | 16 | ```markdown 17 | go get github.com/sacOO7/socketcluster-client-go/scclient 18 | ``` 19 | 20 | Description 21 | ----------- 22 | Create instance of `scclient` by passing url of socketcluster-server end-point 23 | 24 | ```go 25 | //Create a client instance 26 | client := scclient.New("ws://192.168.100.11:8000/socketcluster/"); 27 | 28 | ``` 29 | **Important Note** : Default url to socketcluster end-point is always *ws://somedomainname.com/socketcluster/*. 30 | 31 | #### Registering basic listeners 32 | 33 | Different functions are given as an argument to register listeners 34 | 35 | ```go 36 | package main 37 | 38 | import ( 39 | "github.com/sacOO7/socketcluster-client-go/scclient" 40 | "text/scanner" 41 | "os" 42 | "fmt" 43 | ) 44 | 45 | func onConnect(client scclient.Client) { 46 | fmt.Println("Connected to server") 47 | } 48 | 49 | func onDisconnect(client scclient.Client, err error) { 50 | fmt.Printf("Error: %s\n", err.Error()) 51 | } 52 | 53 | func onConnectError(client scclient.Client, err error) { 54 | fmt.Printf("Error: %s\n", err.Error()) 55 | } 56 | 57 | func onSetAuthentication(client scclient.Client, token string) { 58 | fmt.Println("Auth token received :", token) 59 | 60 | } 61 | 62 | func onAuthentication(client scclient.Client, isAuthenticated bool) { 63 | fmt.Println("Client authenticated :", isAuthenticated) 64 | go startCode(client) 65 | } 66 | 67 | func main() { 68 | var reader scanner.Scanner 69 | client := scclient.New("ws://192.168.100.11:8000/socketcluster/"); 70 | client.SetBasicListener(onConnect, onConnectError, onDisconnect) 71 | client.SetAuthenticationListener(onSetAuthentication, onAuthentication) 72 | go client.Connect() 73 | 74 | fmt.Println("Enter any key to terminate the program") 75 | reader.Init(os.Stdin) 76 | reader.Next() 77 | // os.Exit(0) 78 | } 79 | 80 | func startCode(client scclient.Client) { 81 | // start writing your code from here 82 | // All emit, receive and publish events 83 | } 84 | 85 | ``` 86 | 87 | #### Connecting to server 88 | 89 | - For connecting to server: 90 | 91 | ```go 92 | //This will send websocket handshake request to socketcluster-server 93 | client.Connect() 94 | ``` 95 | 96 | Emitting and listening to events 97 | -------------------------------- 98 | #### Event emitter 99 | 100 | - eventname is name of event and message can be String, boolean, int or structure 101 | 102 | ```go 103 | 104 | client.Emit(eventname,message); 105 | 106 | // client.Emit("chat","This is a sample message") 107 | ``` 108 | 109 | - To send event with acknowledgement 110 | 111 | ```go 112 | 113 | client.EmitAck("chat","This is a sample message", func(eventName string, error interface{}, data interface{}) { 114 | if error == nil { 115 | fmt.Println("Got ack for emit event with data ", data, " and error ", error) 116 | } 117 | }) 118 | 119 | ``` 120 | 121 | #### Event Listener 122 | 123 | - For listening to events : 124 | 125 | The object received can be String, Boolean, Long or GO structure. 126 | 127 | ```go 128 | // Receiver code without sending acknowledgement back 129 | client.On("chat", func(eventName string, data interface{}) { 130 | fmt.Println("Got data ", data, " for event ", eventName) 131 | }) 132 | 133 | ``` 134 | 135 | - To send acknowledgement back to server 136 | 137 | ```go 138 | // Receiver code with ack 139 | client.OnAck("chat", func(eventName string, data interface{}, ack func(error interface{}, data interface{})) { 140 | fmt.Println("Got data ", data, " for event ", eventName) 141 | fmt.Println("Sending back ack for the event") 142 | ack("This is error", "This is data") 143 | }) 144 | 145 | ``` 146 | 147 | Implementing Pub-Sub via channels 148 | --------------------------------- 149 | 150 | #### Creating channel 151 | 152 | - For creating and subscribing to channels: 153 | 154 | ```go 155 | // without acknowledgement 156 | client.Subscribe("mychannel") 157 | 158 | //with acknowledgement 159 | client.SubscribeAck("mychannel", func(channelName string, error interface{}, data interface{}) { 160 | if error == nil { 161 | fmt.Println("Subscribed to channel ", channelName, "successfully") 162 | } 163 | }) 164 | ``` 165 | 166 | 167 | #### Publishing event on channel 168 | 169 | - For publishing event : 170 | 171 | ```go 172 | 173 | // without acknowledgement 174 | client.Publish("mychannel", "This is a data to be published") 175 | 176 | 177 | // with acknowledgement 178 | client.PublishAck("mychannel", "This is a data to be published", func(channelName string, error interface{}, data interface{}) { 179 | if error == nil { 180 | fmt.Println("Data published successfully to channel ", channelName) 181 | } 182 | }) 183 | ``` 184 | 185 | #### Listening to channel 186 | 187 | - For listening to channel event : 188 | 189 | ```go 190 | client.OnChannel("mychannel", func(channelName string, data interface{}) { 191 | fmt.Println("Got data ", data, " for channel ", channelName) 192 | }) 193 | 194 | ``` 195 | 196 | #### Un-subscribing to channel 197 | 198 | ```go 199 | // without acknowledgement 200 | client.Unsubscribe("mychannel") 201 | 202 | // with acknowledgement 203 | client.UnsubscribeAck("mychannel", func(channelName string, error interface{}, data interface{}) { 204 | if error == nil { 205 | fmt.Println("Unsubscribed to channel ", channelName, "successfully") 206 | } 207 | }) 208 | ``` 209 | 210 | #### Closing the connection with server 211 | ```go 212 | client.Disconnect() 213 | ``` 214 | 215 | #### Setting request headers 216 | ```go 217 | client.RequestHeader.Set("Accept-Encoding","gzip, deflate, sdch") 218 | client.RequestHeader.Set("Accept-Language","en-US,en;q=0.8") 219 | client.RequestHeader.Set("Pragma","no-cache") 220 | client.RequestHeader.Set("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36") 221 | 222 | ``` 223 | 224 | #### Setting proxy server 225 | - It can be set using connectionOptions by providing url to proxy server 226 | 227 | ```go 228 | client.ConnectionOptions = gowebsocket.ConnectionOptions { 229 | Proxy: gowebsocket.BuildProxy("http://example.com"), 230 | } 231 | ``` 232 | 233 | #### Setting data compression, ssl verification and subprotocols 234 | 235 | - It can be set using connectionOptions inside socket 236 | 237 | ```go 238 | client.ConnectionOptions = gowebsocket.ConnectionOptions { 239 | UseSSL:true, 240 | UseCompression:true, 241 | Subprotocols: [] string{"chat","superchat"}, 242 | } 243 | ``` 244 | 245 | - ConnectionOptions needs to be applied before connecting to server -------------------------------------------------------------------------------- /SCTestServer/scserver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if test "$#" -ne 1; then 4 | echo "Please provide start or stop as argument" 5 | exit 1 6 | fi 7 | 8 | FOLDER="sc-testserver" 9 | URL="https://github.com/sacOO7/sc-testserver" 10 | 11 | if [ ! -d "$FOLDER" ] ; then 12 | git clone $URL $FOLDER 13 | cd "$FOLDER" 14 | else 15 | cd "$FOLDER" 16 | git pull $URL 17 | fi 18 | 19 | if [ $1 = "start" ]; then 20 | ./runserver 21 | fi 22 | if [ $1 = "stop" ]; then 23 | ./stopserver 24 | fi -------------------------------------------------------------------------------- /commands.txt: -------------------------------------------------------------------------------- 1 | go build -o output ./eventWebsocket 2 | go test ./... 3 | go run fileName -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sacOO7/socketcluster-client-go 2 | 3 | go 1.21.1 4 | 5 | require ( 6 | github.com/rgamba/evtwebsocket v0.0.0-20160725170122-f226ee483c6c 7 | github.com/sacOO7/go-logger v0.0.0-20180719173527-9ac9add5a50d 8 | github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e 9 | github.com/sacOO7/socketcluster-client-go v1.0.0 10 | github.com/stretchr/testify v1.5.1 11 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b 12 | ) 13 | 14 | require ( 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/gorilla/websocket v1.4.1 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | gopkg.in/yaml.v2 v2.2.8 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 5 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 8 | github.com/rgamba/evtwebsocket v0.0.0-20160725170122-f226ee483c6c h1:y8c0hM25dH+CVTuDul35cmsx3zQUDI8yfUnxh2ftLDQ= 9 | github.com/rgamba/evtwebsocket v0.0.0-20160725170122-f226ee483c6c/go.mod h1:fpClUynpFcOmPLy6rXe0pEIoDamYH5s5I0SrbDbF4gk= 10 | github.com/sacOO7/go-logger v0.0.0-20180719173527-9ac9add5a50d h1:5T+fbRuQbpi+WZtB2yfuu59r00F6T2HV/zGYrwX8nvE= 11 | github.com/sacOO7/go-logger v0.0.0-20180719173527-9ac9add5a50d/go.mod h1:L5EJe2k8GwpBoGXDRLAEs58R239jpZuE7NNEtW+T7oo= 12 | github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e h1:yG1sLAkFltiFiwIpKdiA2CVIPxRL4P9OywNnfq45ivg= 13 | github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e/go.mod h1:4a2a9BlxB807BaME8FJzQRLrZwYKj0cWjon25PlIssM= 14 | github.com/sacOO7/socketcluster-client-go v1.0.0 h1:kzLFBvSU2lWlZ/jNeo6yMJbXwyz+cacGsr7jLYUhCI0= 15 | github.com/sacOO7/socketcluster-client-go v1.0.0/go.mod h1:h3nqc4gLr1thtwWn+i7GqCIJ2nMt0Cunr7qN5WhhgfY= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 18 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 19 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 20 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= 21 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 22 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 23 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 24 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 25 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 26 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 27 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 28 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "text/scanner" 7 | 8 | "github.com/sacOO7/socketcluster-client-go/scclient" 9 | ) 10 | 11 | func onConnect(client scclient.Client) { 12 | fmt.Println("Connected to server") 13 | } 14 | 15 | func onDisconnect(client scclient.Client, err error) { 16 | fmt.Printf("Error: %s\n", err.Error()) 17 | os.Exit(1) 18 | } 19 | 20 | func onConnectError(client scclient.Client, err error) { 21 | fmt.Printf("Error: %s\n", err.Error()) 22 | os.Exit(1) 23 | } 24 | 25 | func onSetAuthentication(client scclient.Client, token string) { 26 | fmt.Println("Auth token received :", token) 27 | 28 | } 29 | 30 | func onAuthentication(client scclient.Client, isAuthenticated bool) { 31 | fmt.Println("Client authenticated :", isAuthenticated) 32 | } 33 | 34 | func main() { 35 | var reader scanner.Scanner 36 | client := scclient.New("ws://localhost:8000/socketcluster/") 37 | client.SetBasicListener(onConnect, onConnectError, onDisconnect) 38 | client.SetAuthenticationListener(onSetAuthentication, onAuthentication) 39 | client.EnableLogging() 40 | go client.Connect() 41 | 42 | fmt.Println("Enter any key to terminate the program") 43 | reader.Init(os.Stdin) 44 | reader.Next() 45 | // os.Exit(0) 46 | } 47 | 48 | func start(client scclient.Client) { 49 | // start writing your code from here 50 | } 51 | -------------------------------------------------------------------------------- /scclient/client.go: -------------------------------------------------------------------------------- 1 | package scclient 2 | 3 | import ( 4 | "net/http" 5 | _ "time" 6 | 7 | "github.com/sacOO7/socketcluster-client-go/scclient/models" 8 | "github.com/sacOO7/socketcluster-client-go/scclient/parser" 9 | "github.com/sacOO7/socketcluster-client-go/scclient/utils" 10 | 11 | logging "github.com/sacOO7/go-logger" 12 | "github.com/sacOO7/gowebsocket" 13 | _ "golang.org/x/net/websocket" 14 | ) 15 | 16 | type Client struct { 17 | counter utils.AtomicCounter 18 | authToken *string 19 | url string 20 | socket gowebsocket.Socket 21 | onConnect func(client Client) 22 | onConnectError func(client Client, err error) 23 | onDisconnect func(client Client, err error) 24 | onSetAuthentication func(client Client, token string) 25 | onAuthentication func(client Client, isAuthenticated bool) 26 | ConnectionOptions gowebsocket.ConnectionOptions 27 | RequestHeader http.Header 28 | Listener 29 | } 30 | 31 | func New(url string) Client { 32 | 33 | return Client{ 34 | url: url, 35 | counter: utils.AtomicCounter{Counter: 0}, 36 | Listener: Init()} 37 | } 38 | 39 | func (client *Client) IsConnected() bool { 40 | return client.socket.IsConnected 41 | } 42 | 43 | func (client *Client) EnableLogging() { 44 | scLogger.SetLevel(logging.TRACE) 45 | } 46 | 47 | func (client *Client) GetLogger() logging.Logger { 48 | return scLogger 49 | } 50 | 51 | func (client *Client) SetAuthToken(token string) { 52 | client.authToken = &token 53 | } 54 | 55 | func (client *Client) GetAuthToken() string { 56 | return *client.authToken 57 | } 58 | 59 | func (client *Client) SetBasicListener(onConnect func(client Client), onConnectError func(client Client, err error), onDisconnect func(client Client, err error)) { 60 | client.onConnect = onConnect 61 | client.onConnectError = onConnectError 62 | client.onDisconnect = onDisconnect 63 | } 64 | 65 | func (client *Client) SetAuthenticationListener(onSetAuthentication func(client Client, token string), onAuthentication func(client Client, isAuthenticated bool)) { 66 | client.onSetAuthentication = onSetAuthentication 67 | client.onAuthentication = onAuthentication 68 | } 69 | 70 | func (client *Client) registerCallbacks() { 71 | 72 | client.socket.OnConnected = func(socket gowebsocket.Socket) { 73 | client.counter.Reset() 74 | client.sendHandshake() 75 | if client.onConnect != nil { 76 | client.onConnect(*client) 77 | } 78 | } 79 | client.socket.OnConnectError = func(err error, socket gowebsocket.Socket) { 80 | if err != nil { 81 | if client.onConnectError != nil { 82 | client.onConnectError(*client, err) 83 | } 84 | } 85 | } 86 | client.socket.OnTextMessage = func(message string, socket gowebsocket.Socket) { 87 | scLogger.Info.Printf("%s", message) 88 | 89 | if message == "" { 90 | client.socket.SendText("") 91 | } else if message == "#1" { //protocol v1 ping 92 | client.socket.SendText("#2") 93 | } else { 94 | var messageObject = utils.DeserializeDataFromString(message) 95 | data, rid, cid, eventname, error, err := parser.GetMessageDetails(messageObject) 96 | if err != nil { 97 | scLogger.Trace.Println("Invalid message received '", err.Error(), "'") 98 | return 99 | } 100 | 101 | parseresult := parser.Parse(rid, cid, eventname) 102 | 103 | switch parseresult { 104 | case parser.ISAUTHENTICATED: 105 | isAuthenticated := utils.GetIsAuthenticated(messageObject) 106 | if client.onAuthentication != nil { 107 | client.onAuthentication(*client, isAuthenticated) 108 | } 109 | case parser.SETTOKEN: 110 | scLogger.Trace.Println("Set token event received") 111 | token := utils.GetAuthToken(messageObject) 112 | if client.onSetAuthentication != nil { 113 | client.onSetAuthentication(*client, token) 114 | } 115 | 116 | case parser.REMOVETOKEN: 117 | scLogger.Trace.Println("Remove token event received") 118 | client.authToken = nil 119 | case parser.EVENT: 120 | scLogger.Trace.Println("Received data for event :: ", eventname) 121 | if client.hasEventAck(eventname.(string)) { 122 | client.handleOnAckListener(eventname.(string), data, client.ack(cid)) 123 | } else { 124 | client.handleOnListener(eventname.(string), data) 125 | } 126 | case parser.ACKRECEIVE: 127 | client.handleEmitAck(rid, error, data) 128 | case parser.PUBLISH: 129 | channel := models.GetChannelObject(data) 130 | scLogger.Trace.Println("Publish event received for channel :: ", channel.Channel) 131 | client.handleOnListener(channel.Channel, channel.Data) 132 | } 133 | } 134 | } 135 | client.socket.OnDisconnected = func(err error, socket gowebsocket.Socket) { 136 | if client.onDisconnect != nil { 137 | client.onDisconnect(*client, err) 138 | } 139 | return 140 | } 141 | 142 | } 143 | 144 | func (client *Client) Connect() { 145 | client.socket = gowebsocket.New(client.url) 146 | client.registerCallbacks() 147 | // Connect 148 | client.socket.ConnectionOptions = client.ConnectionOptions 149 | client.socket.RequestHeader = client.RequestHeader 150 | client.socket.Connect() 151 | } 152 | 153 | func (client *Client) sendHandshake() { 154 | handshake := utils.SerializeDataIntoString(models.GetHandshakeObject(client.authToken, int(client.counter.IncrementAndGet()))) 155 | client.socket.SendText(handshake) 156 | } 157 | 158 | func (client *Client) ack(cid int) func(error interface{}, data interface{}) { 159 | return func(error interface{}, data interface{}) { 160 | ackObject := models.GetReceiveEventObject(data, error, cid) 161 | ackData := utils.SerializeDataIntoString(ackObject) 162 | client.socket.SendText(ackData) 163 | } 164 | } 165 | 166 | func (client *Client) Emit(eventName string, data interface{}) { 167 | emitObject := models.GetEmitEventObject(eventName, data, int(client.counter.IncrementAndGet())) 168 | emitData := utils.SerializeDataIntoString(emitObject) 169 | client.socket.SendText(emitData) 170 | } 171 | 172 | func (client *Client) EmitAck(eventName string, data interface{}, ack func(eventName string, error interface{}, data interface{})) { 173 | id := int(client.counter.IncrementAndGet()) 174 | emitObject := models.GetEmitEventObject(eventName, data, id) 175 | emitData := utils.SerializeDataIntoString(emitObject) 176 | client.putEmitAck(id, eventName, ack) 177 | client.socket.SendText(emitData) 178 | } 179 | 180 | func (client *Client) Subscribe(channelName string) { 181 | subscribeObject := models.GetSubscribeEventObject(channelName, int(client.counter.IncrementAndGet())) 182 | subscribeData := utils.SerializeDataIntoString(subscribeObject) 183 | client.socket.SendText(subscribeData) 184 | } 185 | 186 | func (client *Client) SubscribeAck(channelName string, ack func(eventName string, error interface{}, data interface{})) { 187 | id := int(client.counter.IncrementAndGet()) 188 | subscribeObject := models.GetSubscribeEventObject(channelName, id) 189 | subscribeData := utils.SerializeDataIntoString(subscribeObject) 190 | client.putEmitAck(id, channelName, ack) 191 | client.socket.SendText(subscribeData) 192 | } 193 | 194 | func (client *Client) Unsubscribe(channelName string) { 195 | unsubscribeObject := models.GetUnsubscribeEventObject(channelName, int(client.counter.IncrementAndGet())) 196 | unsubscribeData := utils.SerializeDataIntoString(unsubscribeObject) 197 | client.socket.SendText(unsubscribeData) 198 | } 199 | 200 | func (client *Client) UnsubscribeAck(channelName string, ack func(eventName string, error interface{}, data interface{})) { 201 | id := int(client.counter.IncrementAndGet()) 202 | unsubscribeObject := models.GetUnsubscribeEventObject(channelName, id) 203 | unsubscribeData := utils.SerializeDataIntoString(unsubscribeObject) 204 | client.putEmitAck(id, channelName, ack) 205 | client.socket.SendText(unsubscribeData) 206 | } 207 | 208 | func (client *Client) Publish(channelName string, data interface{}) { 209 | publishObject := models.GetPublishEventObject(channelName, data, int(client.counter.IncrementAndGet())) 210 | publishData := utils.SerializeDataIntoString(publishObject) 211 | client.socket.SendText(publishData) 212 | } 213 | 214 | func (client *Client) PublishAck(channelName string, data interface{}, ack func(eventName string, error interface{}, data interface{})) { 215 | id := int(client.counter.IncrementAndGet()) 216 | publishObject := models.GetPublishEventObject(channelName, data, id) 217 | publishData := utils.SerializeDataIntoString(publishObject) 218 | client.putEmitAck(id, channelName, ack) 219 | client.socket.SendText(publishData) 220 | } 221 | 222 | func (client *Client) OnChannel(eventName string, ack func(eventName string, data interface{})) { 223 | client.putOnListener(eventName, ack) 224 | } 225 | 226 | func (client *Client) On(eventName string, ack func(eventName string, data interface{})) { 227 | client.putOnListener(eventName, ack) 228 | } 229 | 230 | func (client *Client) OnAck(eventName string, ack func(eventName string, data interface{}, ack func(error interface{}, data interface{}))) { 231 | client.putOnAckListener(eventName, ack) 232 | } 233 | 234 | func (client *Client) Disconnect() { 235 | client.socket.Close() 236 | } 237 | -------------------------------------------------------------------------------- /scclient/event_listener.go: -------------------------------------------------------------------------------- 1 | package scclient 2 | 3 | import ( 4 | "reflect" 5 | 6 | logging "github.com/sacOO7/go-logger" 7 | ) 8 | 9 | type Empty struct{} 10 | 11 | var scLogger = logging.GetLogger(reflect.TypeOf(Empty{}).PkgPath()).SetLevel(logging.OFF) 12 | 13 | type Listener struct { 14 | emitAckListener map[int][]interface{} 15 | onListener map[string]func(eventName string, data interface{}) 16 | onAckListener map[string]func(eventName string, data interface{}, ack func(error interface{}, data interface{})) 17 | } 18 | 19 | func Init() Listener { 20 | return Listener{ 21 | emitAckListener: make(map[int][]interface{}), 22 | onListener: make(map[string]func(eventName string, data interface{})), 23 | onAckListener: make(map[string]func(eventName string, data interface{}, ack func(error interface{}, data interface{}))), 24 | } 25 | } 26 | 27 | func (listener *Listener) putEmitAck(id int, eventName string, ack func(eventName string, error interface{}, data interface{})) { 28 | listener.emitAckListener[id] = []interface{}{eventName, ack} 29 | } 30 | 31 | func (listener *Listener) handleEmitAck(id int, error interface{}, data interface{}) { 32 | ackObject := listener.emitAckListener[id] 33 | if ackObject != nil { 34 | eventName := ackObject[0].(string) 35 | scLogger.Trace.Println("Ack received for event :: ", eventName) 36 | ack := ackObject[1].(func(eventName string, error interface{}, data interface{})) 37 | ack(eventName, error, data) 38 | } else { 39 | scLogger.Warning.Println("Ack function not found for rid :: ", id) 40 | } 41 | } 42 | 43 | func (listener *Listener) putOnListener(eventName string, onListener func(eventName string, data interface{})) { 44 | listener.onListener[eventName] = onListener 45 | } 46 | 47 | func (listener *Listener) handleOnListener(eventName string, data interface{}) { 48 | on := listener.onListener[eventName] 49 | if on != nil { 50 | on(eventName, data) 51 | } 52 | } 53 | 54 | func (listener *Listener) putOnAckListener(eventName string, onAckListener func(eventName string, data interface{}, ack func(error interface{}, data interface{}))) { 55 | listener.onAckListener[eventName] = onAckListener 56 | } 57 | 58 | func (listener *Listener) handleOnAckListener(eventName string, data interface{}, ack func(error interface{}, data interface{})) { 59 | onAck := listener.onAckListener[eventName] 60 | if onAck != nil { 61 | onAck(eventName, data, ack) 62 | } 63 | } 64 | 65 | func (listener *Listener) hasEventAck(eventName string) bool { 66 | return listener.onAckListener[eventName] != nil 67 | } 68 | -------------------------------------------------------------------------------- /scclient/jsclient.go: -------------------------------------------------------------------------------- 1 | package scclient 2 | 3 | import ( 4 | "github.com/sacOO7/socketcluster-client-go/scclient/models" 5 | "github.com/sacOO7/socketcluster-client-go/scclient/utils" 6 | ) 7 | 8 | func (client *Client) Transmit(eventName string, data interface{}) { 9 | transmitObject := models.GetTransmitEventObject(eventName, data) 10 | transmitData := utils.SerializeDataIntoString(transmitObject) 11 | client.socket.SendText(transmitData) 12 | } -------------------------------------------------------------------------------- /scclient/models/event.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type TransmitEvent struct { 4 | Event string `json:"event"` 5 | Data interface{} `json:"data"` 6 | } 7 | 8 | type EmitEvent struct { 9 | Event string `json:"event"` 10 | Data interface{} `json:"data"` 11 | Cid int `json:"cid"` 12 | } 13 | 14 | type ReceiveEvent struct { 15 | Data interface{} `json:"data"` 16 | Error interface{} `json:"error"` 17 | Rid int `json:"rid"` 18 | } 19 | 20 | type Channel struct { 21 | Channel string `json:"channel"` 22 | Data interface{} `json:"data,omitempty"` 23 | } 24 | 25 | func GetTransmitEventObject(eventname string, data interface{}) TransmitEvent { 26 | return TransmitEvent{ 27 | Event: eventname, 28 | Data: data, 29 | } 30 | } 31 | 32 | func GetEmitEventObject(eventname string, data interface{}, messageId int) EmitEvent { 33 | return EmitEvent{ 34 | Event: eventname, 35 | Data: data, 36 | Cid: messageId, 37 | } 38 | } 39 | 40 | func GetReceiveEventObject(data interface{}, error interface{}, messageId int) ReceiveEvent { 41 | return ReceiveEvent{ 42 | Data: data, 43 | Error: error, 44 | Rid: messageId, 45 | } 46 | } 47 | 48 | func GetChannelObject(data interface{}) Channel { 49 | channelObject := data.(map[string]interface{}) 50 | return Channel{Channel: channelObject["channel"].(string), Data: channelObject["data"]} 51 | } 52 | 53 | func GetSubscribeEventObject(channelName string, messageId int) EmitEvent { 54 | return EmitEvent{ 55 | Event: "#subscribe", 56 | Data: Channel{Channel: channelName}, 57 | Cid: messageId, 58 | } 59 | } 60 | 61 | func GetUnsubscribeEventObject(channelName string, messageId int) EmitEvent { 62 | return EmitEvent{ 63 | Event: "#unsubscribe", 64 | Data: Channel{Channel: channelName}, 65 | Cid: messageId, 66 | } 67 | } 68 | 69 | func GetPublishEventObject(channelName string, data interface{}, messageId int) EmitEvent { 70 | return EmitEvent{ 71 | Event: "#publish", 72 | Data: Channel{Channel: channelName, Data: data}, 73 | Cid: messageId, 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /scclient/models/handshake.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type AuthData struct { 4 | AuthToken *string `json:"authToken"` 5 | } 6 | 7 | type HandShake struct { 8 | Event string `json:"event"` 9 | Data AuthData `json:"data"` 10 | Cid int `json:"cid"` 11 | } 12 | 13 | func GetHandshakeObject(authToken *string, messageId int) HandShake { 14 | return HandShake{ 15 | Event: "#handshake", 16 | Data: AuthData{ 17 | AuthToken: authToken, 18 | }, 19 | Cid: messageId, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scclient/parser/messageT.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | type MessageType int 4 | 5 | //go:generate stringer -type=MessageType 6 | 7 | const ( 8 | ISAUTHENTICATED MessageType = iota 9 | PUBLISH 10 | REMOVETOKEN 11 | SETTOKEN 12 | EVENT 13 | ACKRECEIVE 14 | ) 15 | -------------------------------------------------------------------------------- /scclient/parser/messagetype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=MessageType"; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import "strconv" 6 | 7 | const _MessageType_name = "ISAUTHENTICATEDPUBLISHREMOVETOKENSETTOKENEVENTACKRECEIVE" 8 | 9 | var _MessageType_index = [...]uint8{0, 15, 22, 33, 41, 46, 56} 10 | 11 | func (i MessageType) String() string { 12 | if i < 0 || i >= MessageType(len(_MessageType_index)-1) { 13 | return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")" 14 | } 15 | return _MessageType_name[_MessageType_index[i]:_MessageType_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /scclient/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import "errors" 4 | 5 | func Parse(rid int, cid int, event interface{}) MessageType { 6 | if event != nil { 7 | if event == "#publish" { 8 | return PUBLISH 9 | 10 | } else if event == "#removeAuthToken" { 11 | return REMOVETOKEN 12 | 13 | } else if event == "#setAuthToken" { 14 | return SETTOKEN 15 | 16 | } else { 17 | return EVENT 18 | } 19 | } else if rid == 1 { 20 | return ISAUTHENTICATED 21 | 22 | } else { 23 | return ACKRECEIVE 24 | } 25 | } 26 | 27 | func GetMessageDetails(message interface{}) (data interface{}, rid int, cid int, eventname interface{}, error interface{}, err error) { 28 | //Converting given message into map, with keys and values to that we can parse it 29 | 30 | itemsMap, ok := message.(map[string]interface{}) 31 | if !ok { 32 | err = errors.New("unable to convert message") 33 | return 34 | } 35 | 36 | for itemKey, itemValue := range itemsMap { 37 | switch itemKey { 38 | case "data": 39 | data = itemValue 40 | case "rid": 41 | rid = int(itemValue.(float64)) 42 | case "cid": 43 | cid = int(itemValue.(float64)) 44 | case "event": 45 | eventname = itemValue 46 | case "error": 47 | error = itemValue 48 | } 49 | } 50 | 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /scclient/utils/client_utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func GetAuthToken(message interface{}) string { 4 | itemsMap := message.(map[string]interface{}) 5 | data := itemsMap["data"] 6 | return data.(map[string]interface{})["token"].(string) 7 | } 8 | 9 | func GetIsAuthenticated(message interface{}) bool { 10 | itemsMap := message.(map[string]interface{}) 11 | data := itemsMap["data"] 12 | return data.(map[string]interface{})["isAuthenticated"].(bool) 13 | } 14 | -------------------------------------------------------------------------------- /scclient/utils/counter.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | type AtomicCounter struct { 8 | Counter uint64 9 | } 10 | 11 | func (atomicCounter *AtomicCounter) IncrementAndGet() uint64 { 12 | return atomic.AddUint64(&atomicCounter.Counter, 1) 13 | } 14 | 15 | func (atomicCounter *AtomicCounter) GetAndIncrement() uint64 { 16 | defer atomic.AddUint64(&atomicCounter.Counter, 1) 17 | return atomic.LoadUint64(&atomicCounter.Counter) 18 | } 19 | 20 | func (atomicCounter *AtomicCounter) Reset() { 21 | atomic.StoreUint64(&atomicCounter.Counter, 0) 22 | } 23 | 24 | func (atomicCounter *AtomicCounter) Value() uint64 { 25 | return atomic.LoadUint64(&atomicCounter.Counter) 26 | } 27 | -------------------------------------------------------------------------------- /scclient/utils/miscellaneous.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rgamba/evtwebsocket" 6 | "encoding/json" 7 | ) 8 | 9 | func PrintMessage(message string) { 10 | fmt.Println(message) 11 | } 12 | 13 | func IsEqual(s string, b []byte) bool { 14 | if len(s) != len(b) { 15 | return false 16 | } 17 | for i, x := range b { 18 | if x != s[i] { 19 | return false 20 | } 21 | } 22 | return true 23 | } 24 | 25 | func CreateMessageFromString(message string) evtwebsocket.Msg { 26 | return evtwebsocket.Msg{ 27 | Body: []byte(message), 28 | } 29 | } 30 | 31 | func CreateMessageFromByte(message [] byte) evtwebsocket.Msg { 32 | return evtwebsocket.Msg{ 33 | Body: message, 34 | } 35 | } 36 | 37 | func SerializeData(data interface{}) [] byte { 38 | b, _ := json.Marshal(data) 39 | return b; 40 | } 41 | 42 | func SerializeDataIntoString(data interface{}) string { 43 | b, _ := json.Marshal(data) 44 | return string(b); 45 | } 46 | 47 | func DeserializeData(data [] byte) (jsonObject interface{}) { 48 | json.Unmarshal(data, &jsonObject) 49 | return 50 | } 51 | 52 | func DeserializeDataFromString(data string) (jsonObject interface{}) { 53 | json.Unmarshal([] byte(data), &jsonObject) 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /tests/client_utils_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/sacOO7/socketcluster-client-go/scclient/utils" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestShouldReturnAuthToken(t *testing.T) { 13 | event := "{\"event\":\"#setAuthToken\",\"data\": {\"token\":\"234234\"},\"cid\": 2}" 14 | var jsonObject interface{} 15 | json.Unmarshal([]byte(event), &jsonObject) 16 | actualtoken := utils.GetAuthToken(jsonObject) 17 | assert.Equal(t, "234234", actualtoken) 18 | } 19 | 20 | func TestShouldReturnAuthenticationFlag(t *testing.T) { 21 | event := "{\"rid\":1,\"data\":{\"id\":\"nhI9Ry88h_XpLHwEAAAF\",\"isAuthenticated\":false,\"pingTimeout\":20000}}" 22 | var jsonObject interface{} 23 | json.Unmarshal([]byte(event), &jsonObject) 24 | actualAuthenticationFlag := utils.GetIsAuthenticated(jsonObject) 25 | assert.Equal(t, false, actualAuthenticationFlag) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/counter_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sacOO7/socketcluster-client-go/scclient/utils" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestShouldReturnIncrementedValue(t *testing.T) { 12 | counter := utils.AtomicCounter{ 13 | Counter: 0, 14 | } 15 | 16 | actualValue := counter.IncrementAndGet() 17 | 18 | assert.Equal(t, uint64(1), actualValue) 19 | assert.Equal(t, uint64(1), counter.Value()) 20 | } 21 | 22 | func TestShouldGetAndIncrementValue(t *testing.T) { 23 | counter := utils.AtomicCounter{ 24 | Counter: 0, 25 | } 26 | 27 | actualValue := counter.GetAndIncrement() 28 | 29 | assert.Equal(t, uint64(0), actualValue) 30 | assert.Equal(t, uint64(1), counter.Value()) 31 | } 32 | -------------------------------------------------------------------------------- /tests/miscellaneous_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sacOO7/socketcluster-client-go/scclient/models" 7 | "github.com/sacOO7/socketcluster-client-go/scclient/utils" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestShouldCheckEqual(t *testing.T) { 13 | expected := []byte("mystring") 14 | assert.True(t, utils.IsEqual("mystring", expected), "String and byte [] should be equal") 15 | 16 | } 17 | 18 | func TestShouldSerializeData(t *testing.T) { 19 | 20 | emitEvent := models.EmitEvent{Cid: 2, Data: "My sample data", Event: "chat"} 21 | expectedData := "{\"event\":\"chat\",\"data\":\"My sample data\",\"cid\":2}" 22 | 23 | assert.Equal(t, expectedData, string(utils.SerializeData(emitEvent))) 24 | } 25 | -------------------------------------------------------------------------------- /tests/parser_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/sacOO7/socketcluster-client-go/scclient/parser" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestShouldReturnPublish(t *testing.T) { 13 | var expectedParseResult = parser.PUBLISH 14 | actaulParseResult := parser.Parse(1, 1, "#publish") 15 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return publish") 16 | } 17 | 18 | func TestShouldReturnRemoveAuthToken(t *testing.T) { 19 | var expectedParseResult = parser.REMOVETOKEN 20 | actaulParseResult := parser.Parse(1, 0, "#removeAuthToken") 21 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return remove auth token") 22 | } 23 | 24 | func TestShouldReturnSetAuthToken(t *testing.T) { 25 | var expectedParseResult = parser.SETTOKEN 26 | actaulParseResult := parser.Parse(1, 0, "#setAuthToken") 27 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return set auth token") 28 | } 29 | 30 | func TestShouldReturnEvent(t *testing.T) { 31 | var expectedParseResult = parser.EVENT 32 | actaulParseResult := parser.Parse(1, 0, "chat") 33 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return custom event") 34 | } 35 | 36 | func TestShouldReturnIsAuthenticated(t *testing.T) { 37 | var expectedParseResult = parser.ISAUTHENTICATED 38 | actaulParseResult := parser.Parse(1, 0, nil) 39 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return is authenticated event") 40 | } 41 | 42 | func TestShouldReturnAckReceive(t *testing.T) { 43 | var expectedParseResult = parser.ACKRECEIVE 44 | actaulParseResult := parser.Parse(12, 0, nil) 45 | assert.Equal(t, expectedParseResult, actaulParseResult, "should return ack receive event") 46 | } 47 | 48 | func TestShouldReturnMessageDetails(t *testing.T) { 49 | message := "{\"event\":\"#removeAuthToken\",\"data\":\"This is a sample data\",\"cid\":1, \"rid\":2, \"error\":\"This is a sample error\"}" 50 | var jsonObject interface{} 51 | json.Unmarshal([]byte(message), &jsonObject) 52 | data, rid, cid, eventname, error, err := parser.GetMessageDetails(jsonObject) 53 | assert.Equal(t, "This is a sample data", data) 54 | assert.Equal(t, 2, rid) 55 | assert.Equal(t, 1, cid) 56 | assert.Equal(t, "#removeAuthToken", eventname) 57 | assert.Equal(t, "This is a sample error", error) 58 | assert.Nil(t, err) 59 | } 60 | --------------------------------------------------------------------------------