├── .gitignore ├── LICENSE ├── README.md ├── SocketIOSharp-Example Client ├── App.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Server │ ├── SocketIOSharp Example Server.js │ └── package-lock.json ├── SocketIOSharp-Example Client.csproj └── packages.config ├── SocketIOSharp-Example Server ├── App.config ├── Client │ ├── SocketIOSharp Example Client.js │ └── package-lock.json ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SocketIOSharp-Example Server.csproj └── packages.config ├── SocketIOSharp.sln ├── SocketIOSharp ├── Client │ ├── SocketIOClient.Event.cs │ ├── SocketIOClient.Send.cs │ ├── SocketIOClient.cs │ └── SocketIOClientOption.cs ├── Common │ ├── Abstract │ │ ├── Connection │ │ │ ├── SocketIOConnection.Event.cs │ │ │ └── SocketIOConnection.cs │ │ ├── SocketIO.Emit.cs │ │ └── SocketIO.cs │ ├── Manager │ │ └── SocketIOAckManager.cs │ ├── Packet │ │ ├── Binary │ │ │ └── Constructors │ │ │ │ ├── Constructor.cs │ │ │ │ ├── Deconstructor.cs │ │ │ │ └── Reconstructor.cs │ │ ├── SocketIOAck.cs │ │ ├── SocketIOAckEvent.cs │ │ ├── SocketIOPacket.Static │ │ │ ├── SocketIOPacket.Decoder.cs │ │ │ └── SocketIOPacket.Factory.cs │ │ ├── SocketIOPacket.cs │ │ └── SocketIOPacketType.cs │ ├── SocketIOEvent.cs │ └── SocketIOException.cs ├── Properties │ └── AssemblyInfo.cs ├── Server │ ├── Client │ │ ├── SocketIOSocket.Send.cs │ │ └── SocketIOSocket.cs │ ├── SocketIOServer.Emit.cs │ ├── SocketIOServer.Event.cs │ ├── SocketIOServer.cs │ └── SocketIOServerOption.cs ├── SocketIOSharp.csproj └── packages.config └── icon.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,csharp,visualstudio 3 | # Edit at https://www.gitignore.io/?templates=node,csharp,visualstudio 4 | 5 | ### Csharp ### 6 | ## Ignore Visual Studio temporary files, build results, and 7 | ## files generated by popular Visual Studio add-ons. 8 | ## 9 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 10 | 11 | # User-specific files 12 | *.rsuser 13 | *.suo 14 | *.user 15 | *.userosscache 16 | *.sln.docstates 17 | 18 | # User-specific files (MonoDevelop/Xamarin Studio) 19 | *.userprefs 20 | 21 | # Mono auto generated files 22 | mono_crash.* 23 | 24 | # Build results 25 | [Dd]ebug/ 26 | [Dd]ebugPublic/ 27 | [Rr]elease/ 28 | [Rr]eleases/ 29 | x64/ 30 | x86/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | 38 | # Visual Studio 2015/2017 cache/options directory 39 | .vs/ 40 | # Uncomment if you have tasks that create the project's static files in wwwroot 41 | #wwwroot/ 42 | 43 | # Visual Studio 2017 auto generated files 44 | Generated\ Files/ 45 | 46 | # MSTest test Results 47 | [Tt]est[Rr]esult*/ 48 | [Bb]uild[Ll]og.* 49 | 50 | # NUnit 51 | *.VisualState.xml 52 | TestResult.xml 53 | nunit-*.xml 54 | 55 | # Build Results of an ATL Project 56 | [Dd]ebugPS/ 57 | [Rr]eleasePS/ 58 | dlldata.c 59 | 60 | # Benchmark Results 61 | BenchmarkDotNet.Artifacts/ 62 | 63 | # .NET Core 64 | project.lock.json 65 | project.fragment.lock.json 66 | artifacts/ 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.obj 77 | *.iobj 78 | *.pch 79 | *.pdb 80 | *.ipdb 81 | *.pgc 82 | *.pgd 83 | *.rsp 84 | *.sbr 85 | *.tlb 86 | *.tli 87 | *.tlh 88 | *.tmp 89 | *.tmp_proj 90 | *_wpftmp.csproj 91 | *.log 92 | *.vspscc 93 | *.vssscc 94 | .builds 95 | *.pidb 96 | *.svclog 97 | *.scc 98 | 99 | # Chutzpah Test files 100 | _Chutzpah* 101 | 102 | # Visual C++ cache files 103 | ipch/ 104 | *.aps 105 | *.ncb 106 | *.opendb 107 | *.opensdf 108 | *.sdf 109 | *.cachefile 110 | *.VC.db 111 | *.VC.VC.opendb 112 | 113 | # Visual Studio profiler 114 | *.psess 115 | *.vsp 116 | *.vspx 117 | *.sap 118 | 119 | # Visual Studio Trace Files 120 | *.e2e 121 | 122 | # TFS 2012 Local Workspace 123 | $tf/ 124 | 125 | # Guidance Automation Toolkit 126 | *.gpState 127 | 128 | # ReSharper is a .NET coding add-in 129 | _ReSharper*/ 130 | *.[Rr]e[Ss]harper 131 | *.DotSettings.user 132 | 133 | # JustCode is a .NET coding add-in 134 | .JustCode 135 | 136 | # TeamCity is a build add-in 137 | _TeamCity* 138 | 139 | # DotCover is a Code Coverage Tool 140 | *.dotCover 141 | 142 | # AxoCover is a Code Coverage Tool 143 | .axoCover/* 144 | !.axoCover/settings.json 145 | 146 | # Visual Studio code coverage results 147 | *.coverage 148 | *.coveragexml 149 | 150 | # NCrunch 151 | _NCrunch_* 152 | .*crunch*.local.xml 153 | nCrunchTemp_* 154 | 155 | # MightyMoose 156 | *.mm.* 157 | AutoTest.Net/ 158 | 159 | # Web workbench (sass) 160 | .sass-cache/ 161 | 162 | # Installshield output folder 163 | [Ee]xpress/ 164 | 165 | # DocProject is a documentation generator add-in 166 | DocProject/buildhelp/ 167 | DocProject/Help/*.HxT 168 | DocProject/Help/*.HxC 169 | DocProject/Help/*.hhc 170 | DocProject/Help/*.hhk 171 | DocProject/Help/*.hhp 172 | DocProject/Help/Html2 173 | DocProject/Help/html 174 | 175 | # Click-Once directory 176 | publish/ 177 | 178 | # Publish Web Output 179 | *.[Pp]ublish.xml 180 | *.azurePubxml 181 | # Note: Comment the next line if you want to checkin your web deploy settings, 182 | # but database connection strings (with potential passwords) will be unencrypted 183 | *.pubxml 184 | *.publishproj 185 | 186 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 187 | # checkin your Azure Web App publish settings, but sensitive information contained 188 | # in these scripts will be unencrypted 189 | PublishScripts/ 190 | 191 | # NuGet Packages 192 | *.nupkg 193 | # NuGet Symbol Packages 194 | *.snupkg 195 | # The packages folder can be ignored because of Package Restore 196 | **/[Pp]ackages/* 197 | # except build/, which is used as an MSBuild target. 198 | !**/[Pp]ackages/build/ 199 | # Uncomment if necessary however generally it will be regenerated when needed 200 | #!**/[Pp]ackages/repositories.config 201 | # NuGet v3's project.json files produces more ignorable files 202 | *.nuget.props 203 | *.nuget.targets 204 | 205 | # Microsoft Azure Build Output 206 | csx/ 207 | *.build.csdef 208 | 209 | # Microsoft Azure Emulator 210 | ecf/ 211 | rcf/ 212 | 213 | # Windows Store app package directories and files 214 | AppPackages/ 215 | BundleArtifacts/ 216 | Package.StoreAssociation.xml 217 | _pkginfo.txt 218 | *.appx 219 | *.appxbundle 220 | *.appxupload 221 | 222 | # Visual Studio cache files 223 | # files ending in .cache can be ignored 224 | *.[Cc]ache 225 | # but keep track of directories ending in .cache 226 | !?*.[Cc]ache/ 227 | 228 | # Others 229 | ClientBin/ 230 | ~$* 231 | *~ 232 | *.dbmdl 233 | *.dbproj.schemaview 234 | *.jfm 235 | *.pfx 236 | *.publishsettings 237 | orleans.codegen.cs 238 | 239 | # Including strong name files can present a security risk 240 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 241 | #*.snk 242 | 243 | # Since there are multiple workflows, uncomment next line to ignore bower_components 244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 245 | #bower_components/ 246 | 247 | # RIA/Silverlight projects 248 | Generated_Code/ 249 | 250 | # Backup & report files from converting an old project file 251 | # to a newer Visual Studio version. Backup files are not needed, 252 | # because we have git ;-) 253 | _UpgradeReport_Files/ 254 | Backup*/ 255 | UpgradeLog*.XML 256 | UpgradeLog*.htm 257 | ServiceFabricBackup/ 258 | *.rptproj.bak 259 | 260 | # SQL Server files 261 | *.mdf 262 | *.ldf 263 | *.ndf 264 | 265 | # Business Intelligence projects 266 | *.rdl.data 267 | *.bim.layout 268 | *.bim_*.settings 269 | *.rptproj.rsuser 270 | *- [Bb]ackup.rdl 271 | *- [Bb]ackup ([0-9]).rdl 272 | *- [Bb]ackup ([0-9][0-9]).rdl 273 | 274 | # Microsoft Fakes 275 | FakesAssemblies/ 276 | 277 | # GhostDoc plugin setting file 278 | *.GhostDoc.xml 279 | 280 | # Node.js Tools for Visual Studio 281 | .ntvs_analysis.dat 282 | node_modules/ 283 | 284 | # Visual Studio 6 build log 285 | *.plg 286 | 287 | # Visual Studio 6 workspace options file 288 | *.opt 289 | 290 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 291 | *.vbw 292 | 293 | # Visual Studio LightSwitch build output 294 | **/*.HTMLClient/GeneratedArtifacts 295 | **/*.DesktopClient/GeneratedArtifacts 296 | **/*.DesktopClient/ModelManifest.xml 297 | **/*.Server/GeneratedArtifacts 298 | **/*.Server/ModelManifest.xml 299 | _Pvt_Extensions 300 | 301 | # Paket dependency manager 302 | .paket/paket.exe 303 | paket-files/ 304 | 305 | # FAKE - F# Make 306 | .fake/ 307 | 308 | # CodeRush personal settings 309 | .cr/personal 310 | 311 | # Python Tools for Visual Studio (PTVS) 312 | __pycache__/ 313 | *.pyc 314 | 315 | # Cake - Uncomment if you are using it 316 | # tools/** 317 | # !tools/packages.config 318 | 319 | # Tabs Studio 320 | *.tss 321 | 322 | # Telerik's JustMock configuration file 323 | *.jmconfig 324 | 325 | # BizTalk build output 326 | *.btp.cs 327 | *.btm.cs 328 | *.odx.cs 329 | *.xsd.cs 330 | 331 | # OpenCover UI analysis results 332 | OpenCover/ 333 | 334 | # Azure Stream Analytics local run output 335 | ASALocalRun/ 336 | 337 | # MSBuild Binary and Structured Log 338 | *.binlog 339 | 340 | # NVidia Nsight GPU debugger configuration file 341 | *.nvuser 342 | 343 | # MFractors (Xamarin productivity tool) working folder 344 | .mfractor/ 345 | 346 | # Local History for Visual Studio 347 | .localhistory/ 348 | 349 | # BeatPulse healthcheck temp database 350 | healthchecksdb 351 | 352 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 353 | MigrationBackup/ 354 | 355 | ### Node ### 356 | # Logs 357 | logs 358 | npm-debug.log* 359 | yarn-debug.log* 360 | yarn-error.log* 361 | lerna-debug.log* 362 | 363 | # Diagnostic reports (https://nodejs.org/api/report.html) 364 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 365 | 366 | # Runtime data 367 | pids 368 | *.pid 369 | *.seed 370 | *.pid.lock 371 | 372 | # Directory for instrumented libs generated by jscoverage/JSCover 373 | lib-cov 374 | 375 | # Coverage directory used by tools like istanbul 376 | coverage 377 | *.lcov 378 | 379 | # nyc test coverage 380 | .nyc_output 381 | 382 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 383 | .grunt 384 | 385 | # Bower dependency directory (https://bower.io/) 386 | bower_components 387 | 388 | # node-waf configuration 389 | .lock-wscript 390 | 391 | # Compiled binary addons (https://nodejs.org/api/addons.html) 392 | build/Release 393 | 394 | # Dependency directories 395 | jspm_packages/ 396 | 397 | # TypeScript v1 declaration files 398 | typings/ 399 | 400 | # TypeScript cache 401 | *.tsbuildinfo 402 | 403 | # Optional npm cache directory 404 | .npm 405 | 406 | # Optional eslint cache 407 | .eslintcache 408 | 409 | # Optional REPL history 410 | .node_repl_history 411 | 412 | # Output of 'npm pack' 413 | *.tgz 414 | 415 | # Yarn Integrity file 416 | .yarn-integrity 417 | 418 | # dotenv environment variables file 419 | .env 420 | .env.test 421 | 422 | # parcel-bundler cache (https://parceljs.org/) 423 | .cache 424 | 425 | # next.js build output 426 | .next 427 | 428 | # nuxt.js build output 429 | .nuxt 430 | 431 | # rollup.js default build output 432 | dist/ 433 | 434 | # Uncomment the public line if your project uses Gatsby 435 | # https://nextjs.org/blog/next-9-1#public-directory-support 436 | # https://create-react-app.dev/docs/using-the-public-folder/#docsNav 437 | # public 438 | 439 | # Storybook build outputs 440 | .out 441 | .storybook-out 442 | 443 | # vuepress build output 444 | .vuepress/dist 445 | 446 | # Serverless directories 447 | .serverless/ 448 | 449 | # FuseBox cache 450 | .fusebox/ 451 | 452 | # DynamoDB Local files 453 | .dynamodb/ 454 | 455 | # Temporary folders 456 | tmp/ 457 | temp/ 458 | 459 | ### VisualStudio ### 460 | 461 | # User-specific files 462 | 463 | # User-specific files (MonoDevelop/Xamarin Studio) 464 | 465 | # Mono auto generated files 466 | 467 | # Build results 468 | 469 | # Visual Studio 2015/2017 cache/options directory 470 | # Uncomment if you have tasks that create the project's static files in wwwroot 471 | 472 | # Visual Studio 2017 auto generated files 473 | 474 | # MSTest test Results 475 | 476 | # NUnit 477 | 478 | # Build Results of an ATL Project 479 | 480 | # Benchmark Results 481 | 482 | # .NET Core 483 | 484 | # StyleCop 485 | 486 | # Files built by Visual Studio 487 | 488 | # Chutzpah Test files 489 | 490 | # Visual C++ cache files 491 | 492 | # Visual Studio profiler 493 | 494 | # Visual Studio Trace Files 495 | 496 | # TFS 2012 Local Workspace 497 | 498 | # Guidance Automation Toolkit 499 | 500 | # ReSharper is a .NET coding add-in 501 | 502 | # JustCode is a .NET coding add-in 503 | 504 | # TeamCity is a build add-in 505 | 506 | # DotCover is a Code Coverage Tool 507 | 508 | # AxoCover is a Code Coverage Tool 509 | 510 | # Visual Studio code coverage results 511 | 512 | # NCrunch 513 | 514 | # MightyMoose 515 | 516 | # Web workbench (sass) 517 | 518 | # Installshield output folder 519 | 520 | # DocProject is a documentation generator add-in 521 | 522 | # Click-Once directory 523 | 524 | # Publish Web Output 525 | # Note: Comment the next line if you want to checkin your web deploy settings, 526 | # but database connection strings (with potential passwords) will be unencrypted 527 | 528 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 529 | # checkin your Azure Web App publish settings, but sensitive information contained 530 | # in these scripts will be unencrypted 531 | 532 | # NuGet Packages 533 | # NuGet Symbol Packages 534 | # The packages folder can be ignored because of Package Restore 535 | # except build/, which is used as an MSBuild target. 536 | # Uncomment if necessary however generally it will be regenerated when needed 537 | # NuGet v3's project.json files produces more ignorable files 538 | 539 | # Microsoft Azure Build Output 540 | 541 | # Microsoft Azure Emulator 542 | 543 | # Windows Store app package directories and files 544 | 545 | # Visual Studio cache files 546 | # files ending in .cache can be ignored 547 | # but keep track of directories ending in .cache 548 | 549 | # Others 550 | 551 | # Including strong name files can present a security risk 552 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 553 | 554 | # Since there are multiple workflows, uncomment next line to ignore bower_components 555 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 556 | 557 | # RIA/Silverlight projects 558 | 559 | # Backup & report files from converting an old project file 560 | # to a newer Visual Studio version. Backup files are not needed, 561 | # because we have git ;-) 562 | 563 | # SQL Server files 564 | 565 | # Business Intelligence projects 566 | 567 | # Microsoft Fakes 568 | 569 | # GhostDoc plugin setting file 570 | 571 | # Node.js Tools for Visual Studio 572 | 573 | # Visual Studio 6 build log 574 | 575 | # Visual Studio 6 workspace options file 576 | 577 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 578 | 579 | # Visual Studio LightSwitch build output 580 | 581 | # Paket dependency manager 582 | 583 | # FAKE - F# Make 584 | 585 | # CodeRush personal settings 586 | 587 | # Python Tools for Visual Studio (PTVS) 588 | 589 | # Cake - Uncomment if you are using it 590 | # tools/** 591 | # !tools/packages.config 592 | 593 | # Tabs Studio 594 | 595 | # Telerik's JustMock configuration file 596 | 597 | # BizTalk build output 598 | 599 | # OpenCover UI analysis results 600 | 601 | # Azure Stream Analytics local run output 602 | 603 | # MSBuild Binary and Structured Log 604 | 605 | # NVidia Nsight GPU debugger configuration file 606 | 607 | # MFractors (Xamarin productivity tool) working folder 608 | 609 | # Local History for Visual Studio 610 | 611 | # BeatPulse healthcheck temp database 612 | 613 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 614 | 615 | # End of https://www.gitignore.io/api/node,csharp,visualstudio 616 | 617 | .package.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2020 uhm0311 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SocketIOSharp 2 | `SocketIOSharp` is a **Socket.IO protocol revision `4`** library based on `Engine.IO` and `WebSocket` protocol. It depends on [EngineIOSharp](https://github.com/uhm0311/EngineIOSharp) to use `Engine.IO` protocol. 3 | 4 | # Installation 5 | - [Nuget gallery](https://www.nuget.org/packages/SocketIOSharp) 6 | 7 | - Command `Install-Package SocketIOSharp` in nuget package manager console. 8 | 9 | # Usage 10 | ## Client 11 | ### Namespace ### 12 | ```csharp 13 | using EngineIOSharp.Common.Enum; 14 | using SocketIOSharp.Client; 15 | using SocketIOSharp.Common; 16 | ``` 17 | 18 | ### Constructor ### 19 | ```csharp 20 | SocketIOClient client = new SocketIOClient(new SocketIOClientOption(EngineIOScheme.http, "localhost", 9001)); 21 | ``` 22 | 23 | #### SocketIOClientOption #### 24 | - **Essential Parameters** 25 | 26 | - `Scheme` : Scheme to connect to. It can be `EngineIOScheme.http` or `EngineIOScheme.https`. Internally, it supports `ws` and `wss`. 27 | 28 | - `Host` : Host to connect to. 29 | 30 | - `Port` : Port to connect to. 31 | 32 | - **Optional Parameters** 33 | 34 | - `PolicyPort` : Port the policy server listens on. Defaults to `843`. 35 | 36 | - `Path` : Path to connect to. Defaults to `"/socket.io"`. 37 | 38 | - `Reconnection` : Whether to reconnect to server after Socket.IO client is closed or not. 39 | 40 | - `ReconnectionAttempts` : Number of reconnection attempts before giving up. 41 | 42 | - `ReconnectionDelay` : How ms to initially wait before attempting a new reconnection. 43 | 44 | - `ReconnectionDelayMax` : Maximum amount of time to wait between reconnections. Each attempt increases the `ReconnectionDelay` by 2x along with a randomization. 45 | 46 | - `RandomizationFactor` : 0 <= RandomizationFactor <= 1. 47 | 48 | - `Query` : Parameters that will be passed for each request to the server. Defaults to `null`. 49 | 50 | - `Upgrade` : Whether the client should try to upgrade the transport. Defaults to `true`. 51 | 52 | - `RemeberUpgrade` : Whether the client should bypass normal upgrade process when previous websocket connection is succeeded. Defaults to `false`. 53 | 54 | - `ForceBase64` : Forces base 64 encoding for transport. Defaults to `false`. 55 | 56 | - `WithCredentials` : Whether to include credentials such as cookies, authorization headers, TLS client certificates, etc. with polling requests. Defaults to `false`. 57 | 58 | - `TimestampRequests` : Whether to add the timestamp with each transport request. Polling requests are always stamped. Defaults to `null`. 59 | 60 | - `TimestampParam` : Timestamp parameter. Defaults to `"t"`. 61 | 62 | - `Polling` : Whether to include polling transport. Defaults to `true`. 63 | 64 | - `PollingTimeout` : Timeout for polling requests in milliseconds. Defaults to `0`, which waits indefinitely. 65 | 66 | - `WebSocket` : Whether to include websocket transport. Defaults to `true`. 67 | 68 | - `WebSocketSubprotocols` : List of websocket subprotocols. Defaults to `null`. 69 | 70 | - `ExtraHeaders` : Headers that will be passed for each request to the server. Defaults to `null`. 71 | 72 | - `ClientCertificates` : The collection of security certificates that are associated with each request. Defaults to `null`. 73 | 74 | - `ClientCertificateSelectionCallback` : Callback used to select the certificate to supply to the server. Defaults to `null`. 75 | 76 | - `ServerCertificateValidationCallback` : Callback method to validate the server certificate. Defaults to `null` and server certificate will be always validated. 77 | 78 | ### Connect ### 79 | ```csharp 80 | client.Connect(); 81 | ``` 82 | 83 | ### Disconnect ### 84 | ```csharp 85 | client.Close(); 86 | ``` 87 | or 88 | ```csharp 89 | client.Dispose(); 90 | ``` 91 | 92 | Since `SocketIOClient` implements `IDisposable` interface, it will be automatically disconnect when `SocketIOClient.Dispose` is called. 93 | 94 | ### Handlers ### 95 | For convenient usage, it is implemented to can be used as `Javascript` style. 96 | 97 | #### Event handlers #### 98 | ```csharp 99 | client.On(SocketIOClient.Event.CONNECTION, () => 100 | { 101 | Console.WriteLine("Connected!"); 102 | }); 103 | 104 | client.On(SocketIOClient.Event.DISCONNECT, () => 105 | { 106 | Console.WriteLine("Disconnected!"); 107 | }); 108 | 109 | client.On(SocketIOClient.Event.ERROR, (JToken[] Data) => // Type of argument is JToken[]. 110 | { 111 | if (Data != null && Data.Length > 0 && Data[0] != null) 112 | { 113 | Console.WriteLine("Error : " + Data[0]); 114 | } 115 | else 116 | { 117 | Console.WrtieLine("Unkown Error"); 118 | } 119 | }); 120 | 121 | client.On("message", (Data) => // Argument can be used without type. 122 | { 123 | if (Data != null && Data.Length > 0 && Data[0] != null) 124 | { 125 | Console.WriteLine("Message : " + Data[0]); 126 | } 127 | }); 128 | 129 | client.On("CustomEvent", CustomEventHandler); // Handler can be method. 130 | client.On(9001, ItsOverNineThousands); // Type of event is JToken. So, it can be a number. 131 | 132 | client.Off(9001, ItsOverNineThousands); // Remove 9001 event handler. 133 | ``` 134 | 135 | #### ACK handlers #### 136 | ```csharp 137 | client.On("ACK1", (SocketIOAckEvent EventArgument) => 138 | { 139 | // Type of SocketIOAckEvent.Data is JToken[]. 140 | // Type of SocketIOAckEvent.Callback is Action. 141 | 142 | Console.Write("On event ack1 : " + EventArgument.Data); 143 | }); 144 | 145 | client.On("ACK2", (EventArgument) => // Argument can be used without type. 146 | { 147 | Console.Write("On event ack2 : " + EventArgument.Data); 148 | }); 149 | 150 | client.On("ACK3", CustomAckHandler); // Handler can be method. 151 | client.On(42, LifeTheUniverseAndTheEverything); // Type of event is JToken. So, it can be a number. 152 | 153 | client.Off(42, LifeTheUniverseAndTheEverything); // Remove 42 ack handler. 154 | ``` 155 | 156 | ##### SocketIOClient.Event ##### 157 | ```csharp 158 | public static class Event 159 | { 160 | public static readonly string CONNECTION = "connection"; 161 | public static readonly string DISCONNECT = "disconnect"; 162 | public static readonly string ERROR = "error"; 163 | } 164 | ``` 165 | 166 | These are the common basic `Socket.IO` events. 167 | 168 | ### Emit ### 169 | ```csharp 170 | client.Emit("Event without data and ack"); 171 | 172 | client.Emit("Event only with data", "Hello world"); 173 | 174 | client.Emit("Event only with ack, action as lambda", (Data) => Console.WriteLine("ACK : " + Data)); 175 | client.Emit("Event only with ack, action as method", Console.WriteLine); 176 | 177 | client.Emit("Event with data and ack, action as lambda", 9001, (Data) => Console.WriteLine("ACK : " + Data)); 178 | client.Emit("Event with data and ack, action as method", 42, Console.WriteLine); 179 | // Type of data is JToken. So, it can be a number. 180 | ``` 181 | 182 | ## Server 183 | ### Namespace 184 | 185 | ```csharp 186 | using SocketIOSharp.Server; 187 | ``` 188 | 189 | ### Constructor 190 | ```csharp 191 | SocketIOServer server = new SocketIOServer(new SocketIOServerOption(9001)); 192 | ``` 193 | 194 | #### SocketIOServerOption 195 | 196 | - **Essential Parameters** 197 | 198 | - `Port` : Port to listen. 199 | 200 | - **Optional Parameters** 201 | 202 | - `Path` : Path to listen. Defaults to `"/socket.io"`. 203 | 204 | - `Secure` : Whether to secure connections. Defatuls to `false`. 205 | 206 | - `PingTimeout` : How many ms without a pong packet to consider the connection closed. Defatuls to `5000`. 207 | 208 | - `PingInterval` : How many ms before sending a new ping packet. Defatuls to `25000`. 209 | 210 | - `UpgradeTimeout` : How many ms before an uncompleted transport upgrade is cancelled. Defatuls to `10000`. 211 | 212 | - `Polling` : Whether to accept polling transport. Defatuls to `true`. 213 | 214 | - `WebSocket` : Whether to accept websocket transport. Defatuls to `true`. 215 | 216 | - `AllowUpgrade` : Whether to allow transport upgrade. Defatuls to `true`. 217 | 218 | - `SetCookie` : Whether to use cookie. Defatuls to `true`. 219 | 220 | - `SIDCookieName` : Name of sid cookie. Defatuls to `"io"`. 221 | 222 | - `Cookies` : Configuration of the cookie that contains the client sid to send as part of handshake response headers. This cookie might be used for sticky-session. Defatuls to `null`. 223 | 224 | - `AllowHttpRequest` : A function that receives a given handshake or upgrade http request as its first parameter, and can decide whether to continue or not. Defatuls to `null`. 225 | 226 | - `AllowWebSocket` : A function that receives a given handshake or upgrade websocket connection as its first parameter, and can decide whether to continue or not. Defatuls to `null`. 227 | 228 | - `InitialData` : An optional packet which will be concatenated to the handshake packet emitted by Engine.IO. Defatuls to `null`. 229 | 230 | - `ServerCertificate` : The certificate used to authenticate the server. Defatuls to `null`. 231 | 232 | - `ClientCertificateValidationCallback` : Callback used to validate the certificate supplied by the client. Defatuls to `null` and client certificate will be always validated. 233 | 234 | ### Start 235 | 236 | ```csharp 237 | server.Start(); 238 | ``` 239 | 240 | ### Stop 241 | 242 | ```csharp 243 | server.Stop(); 244 | ``` 245 | 246 | or 247 | 248 | ```csharp 249 | server.Dispose(); 250 | ``` 251 | 252 | Since `SocketIOServer` implements `IDisposable` interface, it will be automatically stoped when `SocketIOServer.Dispose` is called. 253 | 254 | ### Connection 255 | For convenient usage, it is implemented to can be used as `Javascript` style. 256 | 257 | ```csharp 258 | server.OnConnection((SocketIOSocket socket) => 259 | { 260 | Console.WriteLine("Client connected!"); 261 | 262 | socket.On("input", (Data) => 263 | { 264 | foreach (JToken Token in Data) 265 | { 266 | Console.Write(Token + " "); 267 | } 268 | 269 | Console.WriteLine(); 270 | socket.Emit("echo", Data); 271 | }); 272 | 273 | socket.On(SocketIOEvent.DISCONNECT, () => 274 | { 275 | Console.WriteLine("Client disconnected!"); 276 | }); 277 | }); 278 | ``` 279 | 280 | #### SocketIOSocket 281 | 282 | - `SocketIOSocket` is a type of parameter in `SocketIOServer.OnConnection` event callback. It can be used similarly as `SocketIOClient`. 283 | 284 | ##### Disconnect 285 | 286 | ```csharp 287 | socket.Close(); 288 | ``` 289 | 290 | or 291 | 292 | ```csharp 293 | socket.Dispose(); 294 | ``` 295 | 296 | Since `SocketIOSocket` implements `IDisposable` interface, it will be automatically disconnected when `SocketIOSocket.Dispose` is called. 297 | 298 | ##### Handlers ##### 299 | For convenient usage, it is implemented to can be used as `Javascript` style. 300 | 301 | ###### Event handlers ###### 302 | ```csharp 303 | client.On(SocketIOClient.Event.DISCONNECT, () => 304 | { 305 | Console.WriteLine("Disconnected!"); 306 | }); 307 | 308 | client.On(SocketIOClient.Event.ERROR, (JToken[] Data) => // Type of argument is JToken[]. 309 | { 310 | if (Data != null && Data.Length > 0 && Data[0] != null) 311 | { 312 | Console.WriteLine("Error : " + Data[0]); 313 | } 314 | else 315 | { 316 | Console.WrtieLine("Unkown Error"); 317 | } 318 | }); 319 | 320 | client.On("message", (Data) => // Argument can be used without type. 321 | { 322 | if (Data != null && Data.Length > 0 && Data[0] != null) 323 | { 324 | Console.WriteLine("Message : " + Data[0]); 325 | } 326 | }); 327 | 328 | client.On("CustomEvent", CustomEventHandler); // Handler can be method. 329 | client.On(9001, ItsOverNineThousands); // Type of event is JToken. So, it can be a number. 330 | 331 | client.Off(9001, ItsOverNineThousands); // Remove 9001 event handler. 332 | ``` 333 | 334 | - There is no `SocketIOSocket.On(SocketIOEvent.CONNECTION)` event since it is already opened when `SocketIOServer.OnConnection` event callback is called. 335 | 336 | ###### ACK handlers ###### 337 | ```csharp 338 | client.On("ACK1", (SocketIOAckEvent EventArgument) => 339 | { 340 | // Type of SocketIOAckEvent.Data is JToken[]. 341 | // Type of SocketIOAckEvent.Callback is Action. 342 | 343 | Console.Write("On event ack1 : " + EventArgument.Data); 344 | }); 345 | 346 | client.On("ACK2", (EventArgument) => // Argument can be used without type. 347 | { 348 | Console.Write("On event ack2 : " + EventArgument.Data); 349 | }); 350 | 351 | client.On("ACK3", CustomAckHandler); // Handler can be method. 352 | client.On(42, LifeTheUniverseAndTheEverything); // Type of event is JToken. So, it can be a number. 353 | 354 | client.Off(42, LifeTheUniverseAndTheEverything); // Remove 42 ack handler. 355 | ``` 356 | 357 | ##### Emit ##### 358 | ```csharp 359 | client.Emit("Event without data and ack"); 360 | 361 | client.Emit("Event only with data", "Hello world"); 362 | 363 | client.Emit("Event only with ack, action as lambda", (Data) => Console.WriteLine("ACK : " + Data)); 364 | client.Emit("Event only with ack, action as method", Console.WriteLine); 365 | 366 | client.Emit("Event with data and ack, action as lambda", 9001, (Data) => Console.WriteLine("ACK : " + Data)); 367 | client.Emit("Event with data and ack, action as method", 42, Console.WriteLine); 368 | // Type of data is JToken. So, it can be a number. 369 | ``` 370 | 371 | ### Emit ### 372 | 373 | ```csharp 374 | server.Emit("Event without data and ack"); 375 | 376 | server.Emit("Event only with data", "Hello world"); 377 | 378 | server.Emit("Event only with ack, action as lambda", (Data) => Console.WriteLine("ACK : " + Data)); 379 | server.Emit("Event only with ack, action as method", Console.WriteLine); 380 | 381 | server.Emit("Event with data and ack, action as lambda", 9001, (Data) => Console.WriteLine("ACK : " + Data)); 382 | server.Emit("Event with data and ack, action as method", 42, Console.WriteLine); 383 | // Type of data is JToken. So, it can be a number. 384 | ``` 385 | 386 | # Maintenance 387 | Welcome to report issue or create pull request. I will check it happily. 388 | 389 | # Dependencies 390 | - [EngineIOSharp v1.0.5](https://github.com/uhm0311/EngineIOSharp) 391 | 392 | # License 393 | `SocketIOSharp` is under [The MIT License](https://github.com/uhm0311/SocketIOSharp/blob/master/LICENSE). 394 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/Program.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Common.Enum; 2 | using Newtonsoft.Json.Linq; 3 | using SocketIOSharp.Client; 4 | using SocketIOSharp.Common; 5 | using System; 6 | 7 | namespace SocketIOSharp.Example.Client 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | SocketIOClient client = new SocketIOClient(new SocketIOClientOption(EngineIOScheme.http, "localhost", 9001)); 14 | InitEventHandlers(client); 15 | 16 | client.Connect(); 17 | Console.WriteLine("Input /exit to close connection."); 18 | 19 | string line; 20 | while (!(line = Console.ReadLine()).Equals("/exit")) 21 | { 22 | client.Emit("input", line); 23 | client.Emit("input array", line, line); 24 | } 25 | 26 | client.Close(); 27 | 28 | Console.WriteLine("Press any key to continue..."); 29 | Console.Read(); 30 | } 31 | 32 | static void InitEventHandlers(SocketIOClient client) 33 | { 34 | client.On(SocketIOEvent.CONNECTION, () => 35 | { 36 | Console.WriteLine("Connected!"); 37 | }); 38 | 39 | client.On(SocketIOEvent.DISCONNECT, () => 40 | { 41 | Console.WriteLine(); 42 | Console.WriteLine("Disconnected!"); 43 | }); 44 | 45 | client.On("echo", (Data) => 46 | { 47 | Console.WriteLine("Echo : " + (Data[0].Type == JTokenType.Bytes ? BitConverter.ToString(Data[0].ToObject()) : Data[0])); 48 | }); 49 | 50 | client.On("echo array", (Data) => 51 | { 52 | Console.WriteLine("Echo1 : " + Data[0]); 53 | Console.WriteLine("Echo2 : " + Data[1]); 54 | }); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 6 | // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면 7 | // 이러한 특성 값을 변경하세요. 8 | [assembly: AssemblyTitle("SocketIOSharp-Example")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SocketIOSharp-Example")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 18 | // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면 19 | // 해당 형식에 대해 ComVisible 특성을 true로 설정하세요. 20 | [assembly: ComVisible(false)] 21 | 22 | // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. 23 | [assembly: Guid("b201ca68-e3d3-4f49-a6f2-ba939d34dd21")] 24 | 25 | // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. 26 | // 27 | // 주 버전 28 | // 부 버전 29 | // 빌드 번호 30 | // 수정 버전 31 | // 32 | // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를 33 | // 기본값으로 할 수 있습니다. 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/Server/SocketIOSharp Example Server.js: -------------------------------------------------------------------------------- 1 | var express = require('express')(); 2 | var server = require('http').createServer(express); 3 | 4 | var io = require('socket.io')(server); 5 | var port = 9001; 6 | 7 | server.listen(port, function () { 8 | console.log('Listening on ' + port); 9 | 10 | io.on('connection', function (socket) { 11 | console.log('Client connected!'); 12 | socket.emit('echo', Buffer.from([0, 1, 2, 3, 4, 5])); 13 | 14 | socket.on('input', function (input) { 15 | console.log('Client : ' + input); 16 | 17 | socket.emit('echo', input); 18 | }); 19 | 20 | socket.on('input array', function (input1, input2) { 21 | console.log('Client : ' + input1 + ', ' + input2); 22 | 23 | socket.emit('echo array', input1, input2); 24 | }); 25 | 26 | socket.on('disconnect', function () { 27 | console.log('Client disconnected!'); 28 | }); 29 | }); 30 | }); -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/Server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "accepts": { 6 | "version": "1.3.7", 7 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 8 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 9 | "requires": { 10 | "mime-types": "~2.1.24", 11 | "negotiator": "0.6.2" 12 | } 13 | }, 14 | "after": { 15 | "version": "0.8.2", 16 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 17 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "arraybuffer.slice": { 25 | "version": "0.0.7", 26 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 27 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 28 | }, 29 | "async-limiter": { 30 | "version": "1.0.1", 31 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 32 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 33 | }, 34 | "backo2": { 35 | "version": "1.0.2", 36 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 37 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 38 | }, 39 | "base64-arraybuffer": { 40 | "version": "0.1.5", 41 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 42 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 43 | }, 44 | "base64id": { 45 | "version": "2.0.0", 46 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", 47 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" 48 | }, 49 | "better-assert": { 50 | "version": "1.0.2", 51 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 52 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 53 | "requires": { 54 | "callsite": "1.0.0" 55 | } 56 | }, 57 | "blob": { 58 | "version": "0.0.5", 59 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", 60 | "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" 61 | }, 62 | "body-parser": { 63 | "version": "1.19.0", 64 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 65 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 66 | "requires": { 67 | "bytes": "3.1.0", 68 | "content-type": "~1.0.4", 69 | "debug": "2.6.9", 70 | "depd": "~1.1.2", 71 | "http-errors": "1.7.2", 72 | "iconv-lite": "0.4.24", 73 | "on-finished": "~2.3.0", 74 | "qs": "6.7.0", 75 | "raw-body": "2.4.0", 76 | "type-is": "~1.6.17" 77 | } 78 | }, 79 | "bytes": { 80 | "version": "3.1.0", 81 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 82 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 83 | }, 84 | "callsite": { 85 | "version": "1.0.0", 86 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 87 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 88 | }, 89 | "component-bind": { 90 | "version": "1.0.0", 91 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 92 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 93 | }, 94 | "component-emitter": { 95 | "version": "1.2.1", 96 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 97 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 98 | }, 99 | "component-inherit": { 100 | "version": "0.0.3", 101 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 102 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 103 | }, 104 | "content-disposition": { 105 | "version": "0.5.3", 106 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 107 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 108 | "requires": { 109 | "safe-buffer": "5.1.2" 110 | } 111 | }, 112 | "content-type": { 113 | "version": "1.0.4", 114 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 115 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 116 | }, 117 | "cookie": { 118 | "version": "0.4.0", 119 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 120 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 121 | }, 122 | "cookie-signature": { 123 | "version": "1.0.6", 124 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 125 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 126 | }, 127 | "debug": { 128 | "version": "2.6.9", 129 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 130 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 131 | "requires": { 132 | "ms": "2.0.0" 133 | } 134 | }, 135 | "depd": { 136 | "version": "1.1.2", 137 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 138 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 139 | }, 140 | "destroy": { 141 | "version": "1.0.4", 142 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 143 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 144 | }, 145 | "ee-first": { 146 | "version": "1.1.1", 147 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 148 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 149 | }, 150 | "encodeurl": { 151 | "version": "1.0.2", 152 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 153 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 154 | }, 155 | "engine.io": { 156 | "version": "3.4.0", 157 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz", 158 | "integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==", 159 | "requires": { 160 | "accepts": "~1.3.4", 161 | "base64id": "2.0.0", 162 | "cookie": "0.3.1", 163 | "debug": "~4.1.0", 164 | "engine.io-parser": "~2.2.0", 165 | "ws": "^7.1.2" 166 | }, 167 | "dependencies": { 168 | "cookie": { 169 | "version": "0.3.1", 170 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 171 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 172 | }, 173 | "debug": { 174 | "version": "4.1.1", 175 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 176 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 177 | "requires": { 178 | "ms": "^2.1.1" 179 | } 180 | }, 181 | "ms": { 182 | "version": "2.1.2", 183 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 184 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 185 | } 186 | } 187 | }, 188 | "engine.io-client": { 189 | "version": "3.4.0", 190 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz", 191 | "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==", 192 | "requires": { 193 | "component-emitter": "1.2.1", 194 | "component-inherit": "0.0.3", 195 | "debug": "~4.1.0", 196 | "engine.io-parser": "~2.2.0", 197 | "has-cors": "1.1.0", 198 | "indexof": "0.0.1", 199 | "parseqs": "0.0.5", 200 | "parseuri": "0.0.5", 201 | "ws": "~6.1.0", 202 | "xmlhttprequest-ssl": "~1.5.4", 203 | "yeast": "0.1.2" 204 | }, 205 | "dependencies": { 206 | "debug": { 207 | "version": "4.1.1", 208 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 209 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 210 | "requires": { 211 | "ms": "^2.1.1" 212 | } 213 | }, 214 | "ms": { 215 | "version": "2.1.2", 216 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 217 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 218 | }, 219 | "ws": { 220 | "version": "6.1.4", 221 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", 222 | "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", 223 | "requires": { 224 | "async-limiter": "~1.0.0" 225 | } 226 | } 227 | } 228 | }, 229 | "engine.io-parser": { 230 | "version": "2.2.0", 231 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", 232 | "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", 233 | "requires": { 234 | "after": "0.8.2", 235 | "arraybuffer.slice": "~0.0.7", 236 | "base64-arraybuffer": "0.1.5", 237 | "blob": "0.0.5", 238 | "has-binary2": "~1.0.2" 239 | } 240 | }, 241 | "escape-html": { 242 | "version": "1.0.3", 243 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 244 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 245 | }, 246 | "etag": { 247 | "version": "1.8.1", 248 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 249 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 250 | }, 251 | "express": { 252 | "version": "4.17.1", 253 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 254 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 255 | "requires": { 256 | "accepts": "~1.3.7", 257 | "array-flatten": "1.1.1", 258 | "body-parser": "1.19.0", 259 | "content-disposition": "0.5.3", 260 | "content-type": "~1.0.4", 261 | "cookie": "0.4.0", 262 | "cookie-signature": "1.0.6", 263 | "debug": "2.6.9", 264 | "depd": "~1.1.2", 265 | "encodeurl": "~1.0.2", 266 | "escape-html": "~1.0.3", 267 | "etag": "~1.8.1", 268 | "finalhandler": "~1.1.2", 269 | "fresh": "0.5.2", 270 | "merge-descriptors": "1.0.1", 271 | "methods": "~1.1.2", 272 | "on-finished": "~2.3.0", 273 | "parseurl": "~1.3.3", 274 | "path-to-regexp": "0.1.7", 275 | "proxy-addr": "~2.0.5", 276 | "qs": "6.7.0", 277 | "range-parser": "~1.2.1", 278 | "safe-buffer": "5.1.2", 279 | "send": "0.17.1", 280 | "serve-static": "1.14.1", 281 | "setprototypeof": "1.1.1", 282 | "statuses": "~1.5.0", 283 | "type-is": "~1.6.18", 284 | "utils-merge": "1.0.1", 285 | "vary": "~1.1.2" 286 | } 287 | }, 288 | "finalhandler": { 289 | "version": "1.1.2", 290 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 291 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 292 | "requires": { 293 | "debug": "2.6.9", 294 | "encodeurl": "~1.0.2", 295 | "escape-html": "~1.0.3", 296 | "on-finished": "~2.3.0", 297 | "parseurl": "~1.3.3", 298 | "statuses": "~1.5.0", 299 | "unpipe": "~1.0.0" 300 | } 301 | }, 302 | "forwarded": { 303 | "version": "0.1.2", 304 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 305 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 306 | }, 307 | "fresh": { 308 | "version": "0.5.2", 309 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 310 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 311 | }, 312 | "has-binary2": { 313 | "version": "1.0.3", 314 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 315 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 316 | "requires": { 317 | "isarray": "2.0.1" 318 | } 319 | }, 320 | "has-cors": { 321 | "version": "1.1.0", 322 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 323 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 324 | }, 325 | "http-errors": { 326 | "version": "1.7.2", 327 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 328 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 329 | "requires": { 330 | "depd": "~1.1.2", 331 | "inherits": "2.0.3", 332 | "setprototypeof": "1.1.1", 333 | "statuses": ">= 1.5.0 < 2", 334 | "toidentifier": "1.0.0" 335 | } 336 | }, 337 | "iconv-lite": { 338 | "version": "0.4.24", 339 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 340 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 341 | "requires": { 342 | "safer-buffer": ">= 2.1.2 < 3" 343 | } 344 | }, 345 | "indexof": { 346 | "version": "0.0.1", 347 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 348 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 349 | }, 350 | "inherits": { 351 | "version": "2.0.3", 352 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 353 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 354 | }, 355 | "ipaddr.js": { 356 | "version": "1.9.1", 357 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 358 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 359 | }, 360 | "isarray": { 361 | "version": "2.0.1", 362 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 363 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 364 | }, 365 | "media-typer": { 366 | "version": "0.3.0", 367 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 368 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 369 | }, 370 | "merge-descriptors": { 371 | "version": "1.0.1", 372 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 373 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 374 | }, 375 | "methods": { 376 | "version": "1.1.2", 377 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 378 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 379 | }, 380 | "mime": { 381 | "version": "1.6.0", 382 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 383 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 384 | }, 385 | "mime-db": { 386 | "version": "1.43.0", 387 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", 388 | "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" 389 | }, 390 | "mime-types": { 391 | "version": "2.1.26", 392 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", 393 | "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", 394 | "requires": { 395 | "mime-db": "1.43.0" 396 | } 397 | }, 398 | "ms": { 399 | "version": "2.0.0", 400 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 401 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 402 | }, 403 | "negotiator": { 404 | "version": "0.6.2", 405 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 406 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 407 | }, 408 | "object-component": { 409 | "version": "0.0.3", 410 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 411 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 412 | }, 413 | "on-finished": { 414 | "version": "2.3.0", 415 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 416 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 417 | "requires": { 418 | "ee-first": "1.1.1" 419 | } 420 | }, 421 | "parseqs": { 422 | "version": "0.0.5", 423 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 424 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 425 | "requires": { 426 | "better-assert": "~1.0.0" 427 | } 428 | }, 429 | "parseuri": { 430 | "version": "0.0.5", 431 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 432 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 433 | "requires": { 434 | "better-assert": "~1.0.0" 435 | } 436 | }, 437 | "parseurl": { 438 | "version": "1.3.3", 439 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 440 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 441 | }, 442 | "path-to-regexp": { 443 | "version": "0.1.7", 444 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 445 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 446 | }, 447 | "proxy-addr": { 448 | "version": "2.0.6", 449 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", 450 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 451 | "requires": { 452 | "forwarded": "~0.1.2", 453 | "ipaddr.js": "1.9.1" 454 | } 455 | }, 456 | "qs": { 457 | "version": "6.7.0", 458 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 459 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 460 | }, 461 | "range-parser": { 462 | "version": "1.2.1", 463 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 464 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 465 | }, 466 | "raw-body": { 467 | "version": "2.4.0", 468 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 469 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 470 | "requires": { 471 | "bytes": "3.1.0", 472 | "http-errors": "1.7.2", 473 | "iconv-lite": "0.4.24", 474 | "unpipe": "1.0.0" 475 | } 476 | }, 477 | "safe-buffer": { 478 | "version": "5.1.2", 479 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 480 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 481 | }, 482 | "safer-buffer": { 483 | "version": "2.1.2", 484 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 485 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 486 | }, 487 | "send": { 488 | "version": "0.17.1", 489 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 490 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 491 | "requires": { 492 | "debug": "2.6.9", 493 | "depd": "~1.1.2", 494 | "destroy": "~1.0.4", 495 | "encodeurl": "~1.0.2", 496 | "escape-html": "~1.0.3", 497 | "etag": "~1.8.1", 498 | "fresh": "0.5.2", 499 | "http-errors": "~1.7.2", 500 | "mime": "1.6.0", 501 | "ms": "2.1.1", 502 | "on-finished": "~2.3.0", 503 | "range-parser": "~1.2.1", 504 | "statuses": "~1.5.0" 505 | }, 506 | "dependencies": { 507 | "ms": { 508 | "version": "2.1.1", 509 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 510 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 511 | } 512 | } 513 | }, 514 | "serve-static": { 515 | "version": "1.14.1", 516 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 517 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 518 | "requires": { 519 | "encodeurl": "~1.0.2", 520 | "escape-html": "~1.0.3", 521 | "parseurl": "~1.3.3", 522 | "send": "0.17.1" 523 | } 524 | }, 525 | "setprototypeof": { 526 | "version": "1.1.1", 527 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 528 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 529 | }, 530 | "socket.io": { 531 | "version": "2.3.0", 532 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", 533 | "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==", 534 | "requires": { 535 | "debug": "~4.1.0", 536 | "engine.io": "~3.4.0", 537 | "has-binary2": "~1.0.2", 538 | "socket.io-adapter": "~1.1.0", 539 | "socket.io-client": "2.3.0", 540 | "socket.io-parser": "~3.4.0" 541 | }, 542 | "dependencies": { 543 | "debug": { 544 | "version": "4.1.1", 545 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 546 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 547 | "requires": { 548 | "ms": "^2.1.1" 549 | } 550 | }, 551 | "ms": { 552 | "version": "2.1.2", 553 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 554 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 555 | } 556 | } 557 | }, 558 | "socket.io-adapter": { 559 | "version": "1.1.2", 560 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", 561 | "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" 562 | }, 563 | "socket.io-client": { 564 | "version": "2.3.0", 565 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", 566 | "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", 567 | "requires": { 568 | "backo2": "1.0.2", 569 | "base64-arraybuffer": "0.1.5", 570 | "component-bind": "1.0.0", 571 | "component-emitter": "1.2.1", 572 | "debug": "~4.1.0", 573 | "engine.io-client": "~3.4.0", 574 | "has-binary2": "~1.0.2", 575 | "has-cors": "1.1.0", 576 | "indexof": "0.0.1", 577 | "object-component": "0.0.3", 578 | "parseqs": "0.0.5", 579 | "parseuri": "0.0.5", 580 | "socket.io-parser": "~3.3.0", 581 | "to-array": "0.1.4" 582 | }, 583 | "dependencies": { 584 | "debug": { 585 | "version": "4.1.1", 586 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 587 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 588 | "requires": { 589 | "ms": "^2.1.1" 590 | } 591 | }, 592 | "ms": { 593 | "version": "2.1.2", 594 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 595 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 596 | }, 597 | "socket.io-parser": { 598 | "version": "3.3.0", 599 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", 600 | "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", 601 | "requires": { 602 | "component-emitter": "1.2.1", 603 | "debug": "~3.1.0", 604 | "isarray": "2.0.1" 605 | }, 606 | "dependencies": { 607 | "debug": { 608 | "version": "3.1.0", 609 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 610 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 611 | "requires": { 612 | "ms": "2.0.0" 613 | } 614 | }, 615 | "ms": { 616 | "version": "2.0.0", 617 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 618 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 619 | } 620 | } 621 | } 622 | } 623 | }, 624 | "socket.io-parser": { 625 | "version": "3.4.0", 626 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz", 627 | "integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==", 628 | "requires": { 629 | "component-emitter": "1.2.1", 630 | "debug": "~4.1.0", 631 | "isarray": "2.0.1" 632 | }, 633 | "dependencies": { 634 | "debug": { 635 | "version": "4.1.1", 636 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 637 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 638 | "requires": { 639 | "ms": "^2.1.1" 640 | } 641 | }, 642 | "ms": { 643 | "version": "2.1.2", 644 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 645 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 646 | } 647 | } 648 | }, 649 | "statuses": { 650 | "version": "1.5.0", 651 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 652 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 653 | }, 654 | "to-array": { 655 | "version": "0.1.4", 656 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 657 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 658 | }, 659 | "toidentifier": { 660 | "version": "1.0.0", 661 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 662 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 663 | }, 664 | "type-is": { 665 | "version": "1.6.18", 666 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 667 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 668 | "requires": { 669 | "media-typer": "0.3.0", 670 | "mime-types": "~2.1.24" 671 | } 672 | }, 673 | "unpipe": { 674 | "version": "1.0.0", 675 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 676 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 677 | }, 678 | "utils-merge": { 679 | "version": "1.0.1", 680 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 681 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 682 | }, 683 | "vary": { 684 | "version": "1.1.2", 685 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 686 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 687 | }, 688 | "ws": { 689 | "version": "7.2.3", 690 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", 691 | "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" 692 | }, 693 | "xmlhttprequest-ssl": { 694 | "version": "1.5.5", 695 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 696 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 697 | }, 698 | "yeast": { 699 | "version": "0.1.2", 700 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 701 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 702 | } 703 | } 704 | } 705 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/SocketIOSharp-Example Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B201CA68-E3D3-4F49-A6F2-BA939D34DD21} 8 | Exe 9 | SocketIOSharp.Example.Client 10 | SocketIOSharp Example Client 11 | v4.5 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\EmitterSharp.1.1.1.1\lib\net45\EmitterSharp.dll 37 | 38 | 39 | ..\packages\EngineIOSharp.1.0.5\lib\net45\EngineIOSharp.dll 40 | 41 | 42 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 43 | 44 | 45 | ..\packages\SimpleThreadMonitor.1.0.2.1\lib\net45\SimpleThreadMonitor.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ..\packages\WebSocketSharp.CustomHeaders.CustomHttpServer.1.0.2.3\lib\net45\WebSocketSharp.CustomHeaders.CustomHttpServer.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {194be9fb-bea9-4d76-b7bb-f7a7660efe51} 70 | SocketIOSharp 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Client/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/Client/SocketIOSharp Example Client.js: -------------------------------------------------------------------------------- 1 | var socket = require('socket.io-client')('http://localhost:9001/'); 2 | 3 | socket.on('connection', function () { 4 | console.log('connected!'); 5 | socket.emit('input', 'asdasdg'); 6 | }); 7 | 8 | socket.on('echo', function (data) { 9 | console.log('echo : ' + data); 10 | }); 11 | 12 | socket.on('disconnect', function () { 13 | console.log('disconnected!'); 14 | }); 15 | 16 | const readline = require('readline').createInterface({ 17 | input: process.stdin, 18 | output: process.stdout 19 | }); 20 | 21 | function onMessage(message) { 22 | if (message != '/exit') { 23 | socket.emit('input', Buffer.from([0, 1, 2, 3, 4, 5, 6])); 24 | 25 | socket.emit('input', 'Client says, '); 26 | socket.emit('input', message); 27 | 28 | socket.emit('input', 'Client says again, '); 29 | socket.emit('input', 'Hello world!'); 30 | 31 | readline.question('', onMessage); 32 | } else { 33 | process.exit(); 34 | } 35 | } 36 | 37 | console.log('input /exit to exit program.'); 38 | socket.connect(); 39 | 40 | readline.question('', onMessage); -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/Client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "after": { 6 | "version": "0.8.2", 7 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 8 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 9 | }, 10 | "arraybuffer.slice": { 11 | "version": "0.0.7", 12 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 13 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 14 | }, 15 | "async-limiter": { 16 | "version": "1.0.1", 17 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 18 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 19 | }, 20 | "backo2": { 21 | "version": "1.0.2", 22 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 23 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 24 | }, 25 | "base64-arraybuffer": { 26 | "version": "0.1.5", 27 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 28 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 29 | }, 30 | "better-assert": { 31 | "version": "1.0.2", 32 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 33 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 34 | "requires": { 35 | "callsite": "1.0.0" 36 | } 37 | }, 38 | "blob": { 39 | "version": "0.0.5", 40 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", 41 | "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" 42 | }, 43 | "callsite": { 44 | "version": "1.0.0", 45 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 46 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 47 | }, 48 | "component-bind": { 49 | "version": "1.0.0", 50 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 51 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 52 | }, 53 | "component-emitter": { 54 | "version": "1.2.1", 55 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 56 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 57 | }, 58 | "component-inherit": { 59 | "version": "0.0.3", 60 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 61 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 62 | }, 63 | "debug": { 64 | "version": "4.1.1", 65 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 66 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 67 | "requires": { 68 | "ms": "^2.1.1" 69 | } 70 | }, 71 | "engine.io-client": { 72 | "version": "3.4.2", 73 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.2.tgz", 74 | "integrity": "sha512-AWjc1Xg06a6UPFOBAzJf48W1UR/qKYmv/ubgSCumo9GXgvL/xGIvo05dXoBL+2NTLMipDI7in8xK61C17L25xg==", 75 | "requires": { 76 | "component-emitter": "~1.3.0", 77 | "component-inherit": "0.0.3", 78 | "debug": "~4.1.0", 79 | "engine.io-parser": "~2.2.0", 80 | "has-cors": "1.1.0", 81 | "indexof": "0.0.1", 82 | "parseqs": "0.0.5", 83 | "parseuri": "0.0.5", 84 | "ws": "~6.1.0", 85 | "xmlhttprequest-ssl": "~1.5.4", 86 | "yeast": "0.1.2" 87 | }, 88 | "dependencies": { 89 | "component-emitter": { 90 | "version": "1.3.0", 91 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 92 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 93 | } 94 | } 95 | }, 96 | "engine.io-parser": { 97 | "version": "2.2.0", 98 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", 99 | "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", 100 | "requires": { 101 | "after": "0.8.2", 102 | "arraybuffer.slice": "~0.0.7", 103 | "base64-arraybuffer": "0.1.5", 104 | "blob": "0.0.5", 105 | "has-binary2": "~1.0.2" 106 | } 107 | }, 108 | "has-binary2": { 109 | "version": "1.0.3", 110 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 111 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 112 | "requires": { 113 | "isarray": "2.0.1" 114 | } 115 | }, 116 | "has-cors": { 117 | "version": "1.1.0", 118 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 119 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 120 | }, 121 | "indexof": { 122 | "version": "0.0.1", 123 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 124 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 125 | }, 126 | "isarray": { 127 | "version": "2.0.1", 128 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 129 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 130 | }, 131 | "ms": { 132 | "version": "2.1.2", 133 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 134 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 135 | }, 136 | "object-component": { 137 | "version": "0.0.3", 138 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 139 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 140 | }, 141 | "parseqs": { 142 | "version": "0.0.5", 143 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 144 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 145 | "requires": { 146 | "better-assert": "~1.0.0" 147 | } 148 | }, 149 | "parseuri": { 150 | "version": "0.0.5", 151 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 152 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 153 | "requires": { 154 | "better-assert": "~1.0.0" 155 | } 156 | }, 157 | "readline": { 158 | "version": "1.3.0", 159 | "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", 160 | "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=" 161 | }, 162 | "socket.io-client": { 163 | "version": "2.3.0", 164 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", 165 | "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", 166 | "requires": { 167 | "backo2": "1.0.2", 168 | "base64-arraybuffer": "0.1.5", 169 | "component-bind": "1.0.0", 170 | "component-emitter": "1.2.1", 171 | "debug": "~4.1.0", 172 | "engine.io-client": "~3.4.0", 173 | "has-binary2": "~1.0.2", 174 | "has-cors": "1.1.0", 175 | "indexof": "0.0.1", 176 | "object-component": "0.0.3", 177 | "parseqs": "0.0.5", 178 | "parseuri": "0.0.5", 179 | "socket.io-parser": "~3.3.0", 180 | "to-array": "0.1.4" 181 | } 182 | }, 183 | "socket.io-parser": { 184 | "version": "3.3.0", 185 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", 186 | "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", 187 | "requires": { 188 | "component-emitter": "1.2.1", 189 | "debug": "~3.1.0", 190 | "isarray": "2.0.1" 191 | }, 192 | "dependencies": { 193 | "debug": { 194 | "version": "3.1.0", 195 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 196 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 197 | "requires": { 198 | "ms": "2.0.0" 199 | } 200 | }, 201 | "ms": { 202 | "version": "2.0.0", 203 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 204 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 205 | } 206 | } 207 | }, 208 | "to-array": { 209 | "version": "0.1.4", 210 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 211 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 212 | }, 213 | "ws": { 214 | "version": "6.1.4", 215 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", 216 | "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", 217 | "requires": { 218 | "async-limiter": "~1.0.0" 219 | } 220 | }, 221 | "xmlhttprequest-ssl": { 222 | "version": "1.5.5", 223 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 224 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 225 | }, 226 | "yeast": { 227 | "version": "0.1.2", 228 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 229 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using SocketIOSharp.Common; 3 | using SocketIOSharp.Server; 4 | using System; 5 | 6 | namespace SocketIOSharp.Example.Server 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | using (SocketIOServer server = new SocketIOServer(new SocketIOServerOption(9001))) 13 | { 14 | Console.WriteLine("Listening on " + server.Option.Port); 15 | 16 | server.OnConnection((socket) => 17 | { 18 | Console.WriteLine("Client connected!"); 19 | 20 | socket.On("input", (data) => 21 | { 22 | foreach (JToken token in data) 23 | { 24 | Console.Write(token + " "); 25 | } 26 | 27 | Console.WriteLine(); 28 | socket.Emit("echo", data); 29 | }); 30 | 31 | socket.On(SocketIOEvent.DISCONNECT, () => 32 | { 33 | Console.WriteLine("Client disconnected!"); 34 | }); 35 | 36 | socket.Emit("echo", new byte[] { 0, 1, 2, 3, 4, 5 }); 37 | }); 38 | 39 | server.Start(); 40 | 41 | Console.WriteLine("Input /exit to exit program."); 42 | string line; 43 | 44 | while (!(line = Console.ReadLine())?.Trim()?.ToLower()?.Equals("/exit") ?? false) 45 | { 46 | server.Emit("echo", line); 47 | } 48 | } 49 | 50 | Console.WriteLine("Press enter to continue..."); 51 | Console.Read(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 6 | // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면 7 | // 이러한 특성 값을 변경하세요. 8 | [assembly: AssemblyTitle("SocketIOSharp-Example Server")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SocketIOSharp-Example Server")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 18 | // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면 19 | // 해당 형식에 대해 ComVisible 특성을 true로 설정하세요. 20 | [assembly: ComVisible(false)] 21 | 22 | // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. 23 | [assembly: Guid("6979dd27-ba65-4e69-82dc-f6f5a2b1206a")] 24 | 25 | // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. 26 | // 27 | // 주 버전 28 | // 부 버전 29 | // 빌드 번호 30 | // 수정 버전 31 | // 32 | // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를 33 | // 기본값으로 할 수 있습니다. 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/SocketIOSharp-Example Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6979DD27-BA65-4E69-82DC-F6F5A2B1206A} 8 | Exe 9 | SocketIOSharp.Example.Server 10 | SocketIOSharp-Example Server 11 | v4.5 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\EmitterSharp.1.1.1.1\lib\net45\EmitterSharp.dll 37 | 38 | 39 | ..\packages\EngineIOSharp.1.0.5\lib\net45\EngineIOSharp.dll 40 | 41 | 42 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 43 | 44 | 45 | ..\packages\SimpleThreadMonitor.1.0.2.1\lib\net45\SimpleThreadMonitor.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ..\packages\WebSocketSharp.CustomHeaders.CustomHttpServer.1.0.2.3\lib\net45\WebSocketSharp.CustomHeaders.CustomHttpServer.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {194be9fb-bea9-4d76-b7bb-f7a7660efe51} 70 | SocketIOSharp 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /SocketIOSharp-Example Server/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SocketIOSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29905.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocketIOSharp", "SocketIOSharp\SocketIOSharp.csproj", "{194BE9FB-BEA9-4D76-B7BB-F7A7660EFE51}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketIOSharp-Example Client", "SocketIOSharp-Example Client\SocketIOSharp-Example Client.csproj", "{B201CA68-E3D3-4F49-A6F2-BA939D34DD21}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketIOSharp-Example Server", "SocketIOSharp-Example Server\SocketIOSharp-Example Server.csproj", "{6979DD27-BA65-4E69-82DC-F6F5A2B1206A}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {194BE9FB-BEA9-4D76-B7BB-F7A7660EFE51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {194BE9FB-BEA9-4D76-B7BB-F7A7660EFE51}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {194BE9FB-BEA9-4D76-B7BB-F7A7660EFE51}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {194BE9FB-BEA9-4D76-B7BB-F7A7660EFE51}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {B201CA68-E3D3-4F49-A6F2-BA939D34DD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {B201CA68-E3D3-4F49-A6F2-BA939D34DD21}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {B201CA68-E3D3-4F49-A6F2-BA939D34DD21}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {B201CA68-E3D3-4F49-A6F2-BA939D34DD21}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {6979DD27-BA65-4E69-82DC-F6F5A2B1206A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {6979DD27-BA65-4E69-82DC-F6F5A2B1206A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {6979DD27-BA65-4E69-82DC-F6F5A2B1206A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {6979DD27-BA65-4E69-82DC-F6F5A2B1206A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {EAB01B22-D079-468A-B279-92DCFD3372D0} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /SocketIOSharp/Client/SocketIOClient.Event.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Client 2 | { 3 | partial class SocketIOClient 4 | { 5 | private static class Event 6 | { 7 | public static readonly string CONNECT_ERROR = "connect_error"; 8 | 9 | public static readonly string RECONNECT = "reconnect"; 10 | public static readonly string RECONNECT_ATTEMPT = "reconnect_attempt"; 11 | public static readonly string RECONNECTING = "reconnecting"; 12 | 13 | public static readonly string RECONNECT_ERROR = "reconnect_error"; 14 | public static readonly string RECONNECT_FAILED = "reconnect_failed"; 15 | 16 | public static readonly string PING = "ping"; 17 | public static readonly string PONG = "pong"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SocketIOSharp/Client/SocketIOClient.Send.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Client 2 | { 3 | partial class SocketIOClient 4 | { 5 | protected override SocketIOClient Emit(string Data) 6 | { 7 | Client?.Send(Data); 8 | 9 | return this; 10 | } 11 | 12 | protected override SocketIOClient Emit(byte[] RawData) 13 | { 14 | Client?.Send(RawData); 15 | 16 | return this; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SocketIOSharp/Client/SocketIOClient.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Client; 2 | using EngineIOSharp.Common.Enum; 3 | using EngineIOSharp.Common.Packet; 4 | using SocketIOSharp.Common; 5 | using SocketIOSharp.Common.Abstract.Connection; 6 | using System; 7 | using System.Threading; 8 | 9 | namespace SocketIOSharp.Client 10 | { 11 | public partial class SocketIOClient : SocketIOConnection 12 | { 13 | private static readonly Random Random = new Random(); 14 | private DateTime LastPing = DateTime.UtcNow; 15 | 16 | private EngineIOClient Client = null; 17 | private ulong ReconnectionAttempts = 0; 18 | private bool Closing = false; 19 | 20 | public SocketIOClientOption Option { get; private set; } 21 | 22 | public override EngineIOReadyState ReadyState => Client?.ReadyState ?? EngineIOReadyState.CLOSED; 23 | 24 | public SocketIOClient(SocketIOClientOption Option) 25 | { 26 | this.Option = Option; 27 | } 28 | 29 | public SocketIOClient Connect() 30 | { 31 | if (Client == null) 32 | { 33 | ReconnectionAttempts = 0; 34 | Closing = false; 35 | 36 | void Connect() 37 | { 38 | Client = new EngineIOClient(Option); 39 | Client.OnOpen(() => 40 | { 41 | AckManager.SetTimeout(Client.Handshake.PingTimeout); 42 | AckManager.StartTimer(); 43 | 44 | if (ReconnectionAttempts > 0) 45 | { 46 | CallEventHandler(Event.RECONNECT, ReconnectionAttempts); 47 | ReconnectionAttempts = 0; 48 | } 49 | }); 50 | 51 | Client.OnMessage(OnPacket); 52 | Client.OnClose((Exception) => 53 | { 54 | OnDisconnect(Exception); 55 | 56 | if (ReconnectionAttempts == 0) 57 | { 58 | CallEventHandler(Event.CONNECT_ERROR, new SocketIOException("Connect error", Exception).ToString()); 59 | } 60 | else 61 | { 62 | CallEventHandler(Event.RECONNECT_ERROR, new SocketIOException("Reconnect error", Exception).ToString()); 63 | } 64 | 65 | if (!Closing && Option.Reconnection && ReconnectionAttempts < Option.ReconnectionAttempts) 66 | { 67 | ReconnectionAttempts++; 68 | 69 | ThreadPool.QueueUserWorkItem((_) => 70 | { 71 | int Factor = (int)(Option.ReconnectionDelay * Option.RandomizationFactor); 72 | int Delay = Random.Next(Option.ReconnectionDelay - Factor, Option.ReconnectionDelay + Factor + 1); 73 | 74 | Thread.Sleep(Delay); 75 | Option.ReconnectionDelay = Math.Min(Option.ReconnectionDelayMax, Option.ReconnectionDelay * 2); 76 | 77 | CallEventHandler(Event.RECONNECT_ATTEMPT); 78 | Connect(); 79 | 80 | CallEventHandler(Event.RECONNECTING, ReconnectionAttempts); 81 | }); 82 | } 83 | else if (ReconnectionAttempts >= Option.ReconnectionAttempts) 84 | { 85 | CallEventHandler(Event.RECONNECT_FAILED); 86 | } 87 | }); 88 | 89 | Client.On(EngineIOClient.Event.PACKET_CREATE, (Argument) => 90 | { 91 | if ((Argument as EngineIOPacket).Type == EngineIOPacketType.PING) 92 | { 93 | CallEventHandler(Event.PING); 94 | LastPing = DateTime.UtcNow; 95 | } 96 | }); 97 | 98 | Client.On(EngineIOClient.Event.PACKET, (Argument) => 99 | { 100 | if ((Argument as EngineIOPacket).Type == EngineIOPacketType.PONG) 101 | { 102 | CallEventHandler(Event.PONG, DateTime.UtcNow.Subtract(LastPing).TotalMilliseconds); 103 | } 104 | }); 105 | 106 | Client.Connect(); 107 | } 108 | 109 | Connect(); 110 | } 111 | 112 | return this; 113 | } 114 | 115 | public override SocketIOClient Close() 116 | { 117 | Closing = true; 118 | Client?.Close(); 119 | 120 | return this; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /SocketIOSharp/Client/SocketIOClientOption.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Client; 2 | using EngineIOSharp.Common.Enum; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Security; 6 | using System.Security.Cryptography.X509Certificates; 7 | 8 | namespace SocketIOSharp.Client 9 | { 10 | public class SocketIOClientOption : EngineIOClientOption 11 | { 12 | private int _ReconnectionDelay; 13 | private int _ReconnectionDelayMax; 14 | private double _RandomizationFactor; 15 | 16 | public bool Reconnection { get; set; } 17 | public ulong ReconnectionAttempts { get; set; } 18 | 19 | public int ReconnectionDelay 20 | { 21 | get 22 | { 23 | return _ReconnectionDelay; 24 | } 25 | set 26 | { 27 | _ReconnectionDelay = Math.Max(0, value); 28 | } 29 | } 30 | public int ReconnectionDelayMax 31 | { 32 | get 33 | { 34 | return _ReconnectionDelayMax; 35 | } 36 | set 37 | { 38 | _ReconnectionDelayMax = Math.Max(ReconnectionDelay, value); 39 | } 40 | } 41 | public double RandomizationFactor 42 | { 43 | get 44 | { 45 | return _RandomizationFactor; 46 | } 47 | set 48 | { 49 | _RandomizationFactor = Math.Max(0, Math.Min(1, value)); 50 | } 51 | } 52 | 53 | /// 54 | /// Options for Socket.IO client. 55 | /// 56 | /// Scheme to connect to. 57 | /// Host to connect to. 58 | /// Port to connect to. 59 | /// Port the policy server listens on. 60 | /// Path to connect to. 61 | /// Whether to reconnect to server after Socket.IO client is closed or not. 62 | /// Number of reconnection attempts before giving up. 63 | /// How ms to initially wait before attempting a new reconnection. 64 | /// Maximum amount of time to wait between reconnections. Each attempt increases the by 2x along with a randomization. 65 | /// 0 <= <= 1. 66 | /// Parameters that will be passed for each request to the server. 67 | /// Whether the client should try to upgrade the transport. 68 | /// Whether the client should bypass normal upgrade process when previous websocket connection is succeeded. 69 | /// Forces base 64 encoding for transport. 70 | /// Whether to include credentials such as cookies, authorization headers, TLS client certificates, etc. with polling requests. 71 | /// Whether to add the timestamp with each transport request. Polling requests are always stamped. 72 | /// Timestamp parameter. 73 | /// Whether to include polling transport. 74 | /// Timeout for polling requests in milliseconds. 75 | /// Whether to include websocket transport. 76 | /// List of websocket subprotocols. 77 | /// Headers that will be passed for each request to the server. 78 | /// The collection of security certificates that are associated with each request. 79 | /// Callback used to select the certificate to supply to the server. 80 | /// Callback method to validate the server certificate. 81 | public SocketIOClientOption(EngineIOScheme Scheme, string Host, ushort Port, ushort PolicyPort = 843, string Path = "/socket.io", bool Reconnection = true, ulong ReconnectionAttempts = ulong.MaxValue, int ReconnectionDelay = 1000, int ReconnectionDelayMax = 5000, double RandomizationFactor = 0.5, IDictionary Query = null, bool Upgrade = true, bool RemeberUpgrade = false, bool ForceBase64 = false, bool WithCredentials = true, bool? TimestampRequests = null, string TimestampParam = "t", bool Polling = true, int PollingTimeout = 0, bool WebSocket = true, string[] WebSocketSubprotocols = null, IDictionary ExtraHeaders = null, X509CertificateCollection ClientCertificates = null, LocalCertificateSelectionCallback ClientCertificateSelectionCallback = null, RemoteCertificateValidationCallback ServerCertificateValidationCallback = null) : base(Scheme, Host, Port, PolicyPort, Path, PolishQuery(Query), Upgrade, RemeberUpgrade, ForceBase64, WithCredentials, TimestampRequests, TimestampParam, Polling, PollingTimeout, WebSocket, WebSocketSubprotocols, ExtraHeaders, ClientCertificates, ClientCertificateSelectionCallback, ServerCertificateValidationCallback) 82 | { 83 | this.Reconnection = Reconnection; 84 | this.ReconnectionAttempts = ReconnectionAttempts; 85 | 86 | this.ReconnectionDelay = ReconnectionDelay; 87 | this.ReconnectionDelayMax = ReconnectionDelayMax; 88 | this.RandomizationFactor = RandomizationFactor; 89 | } 90 | 91 | private static IDictionary PolishQuery(IDictionary Query) 92 | { 93 | Query = new Dictionary(Query ?? new Dictionary()); 94 | 95 | if (!Query.ContainsKey("EIO")) 96 | { 97 | Query["EIO"] = "4"; 98 | } 99 | 100 | return Query; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Abstract/Connection/SocketIOConnection.Event.cs: -------------------------------------------------------------------------------- 1 | using EmitterSharp; 2 | using Newtonsoft.Json.Linq; 3 | using SocketIOSharp.Common.Packet; 4 | using SocketIOSharp.Common.Packet.Binary.Constructors; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace SocketIOSharp.Common.Abstract.Connection 10 | { 11 | partial class SocketIOConnection 12 | { 13 | protected readonly Reconstructor Reconstructor = new Reconstructor(); 14 | 15 | private readonly SocketIOEventHandlerManager EventHandlerManager = new SocketIOEventHandlerManager(); 16 | private readonly SocketIOAckEventHandlerManager AckEventHandlerManager = new SocketIOAckEventHandlerManager(); 17 | 18 | public TChildClass On(JToken Event, Action Callback) 19 | { 20 | EventHandlerManager.On(Event, Callback); 21 | 22 | return this as TChildClass; 23 | } 24 | 25 | public TChildClass On(JToken Event, Action Callback) 26 | { 27 | EventHandlerManager.On(Event, Callback); 28 | 29 | return this as TChildClass; 30 | } 31 | 32 | public TChildClass Once(JToken Event, Action Callback) 33 | { 34 | EventHandlerManager.Once(Event, Callback); 35 | 36 | return this as TChildClass; 37 | } 38 | 39 | public TChildClass Once(JToken Event, Action Callback) 40 | { 41 | EventHandlerManager.Once(Event, Callback); 42 | 43 | return this as TChildClass; 44 | } 45 | 46 | public TChildClass Off(JToken Event, Action Callback) 47 | { 48 | EventHandlerManager.Off(Event, Callback); 49 | 50 | return this as TChildClass; 51 | } 52 | 53 | public TChildClass Off(JToken Event, Action Callback) 54 | { 55 | EventHandlerManager.Off(Event, Callback); 56 | 57 | return this as TChildClass; 58 | } 59 | 60 | public TChildClass On(JToken Event, Action Callback) 61 | { 62 | AckEventHandlerManager.On(Event, Callback); 63 | 64 | return this as TChildClass; 65 | } 66 | 67 | public TChildClass Once(JToken Event, Action Callback) 68 | { 69 | AckEventHandlerManager.Once(Event, Callback); 70 | 71 | return this as TChildClass; 72 | } 73 | 74 | public TChildClass Off(JToken Event, Action Callback) 75 | { 76 | AckEventHandlerManager.Off(Event, Callback); 77 | 78 | return this as TChildClass; 79 | } 80 | 81 | private void CallHandler(SocketIOPacket Packet) 82 | { 83 | if (Packet != null && Packet.JsonData != null) 84 | { 85 | Queue Temp = new Queue(((JArray)Packet.JsonData).ToArray()); 86 | 87 | if (Temp.Count > 0) 88 | { 89 | JToken Event = Temp.Dequeue(); 90 | JToken[] Data = Temp.ToArray(); 91 | 92 | CallEventHandler(Event, Data); 93 | CallAckEventHandler(Event, Packet.ID, Data); 94 | } 95 | } 96 | } 97 | 98 | private void CallAckEventHandler(JToken Event, int PacketID, params JToken[] Data) 99 | { 100 | if (Event != null) 101 | { 102 | Action Callback = null; 103 | 104 | if (PacketID >= 0) 105 | { 106 | Callback = (AckData) => 107 | { 108 | Emit(SocketIOPacket.CreateAckPacket(new JArray(AckData), PacketID)); 109 | }; 110 | } 111 | 112 | AckEventHandlerManager.Emit(Event, new SocketIOAckEvent(Data, Callback)); 113 | } 114 | } 115 | 116 | protected void CallEventHandler(JToken Event, params JToken[] Data) 117 | { 118 | if (Event != null) 119 | { 120 | EventHandlerManager.Emit(Event, Data); 121 | } 122 | } 123 | 124 | private class SocketIOEventHandlerManager : Emitter 125 | { 126 | 127 | } 128 | 129 | private class SocketIOAckEventHandlerManager : Emitter 130 | { 131 | 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Abstract/Connection/SocketIOConnection.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Common.Enum; 2 | using EngineIOSharp.Common.Packet; 3 | using Newtonsoft.Json.Linq; 4 | using SocketIOSharp.Common.Packet; 5 | using System; 6 | using System.Linq; 7 | 8 | namespace SocketIOSharp.Common.Abstract.Connection 9 | { 10 | public abstract partial class SocketIOConnection : SocketIO where TChildClass : SocketIOConnection 11 | { 12 | public abstract EngineIOReadyState ReadyState { get; } 13 | 14 | public abstract TChildClass Close(); 15 | 16 | public override void Dispose() 17 | { 18 | Close(); 19 | } 20 | 21 | protected void OnPacket(EngineIOPacket Packet) 22 | { 23 | OnPacket(SocketIOPacket.Decode(Packet)); 24 | } 25 | 26 | private void OnPacket(SocketIOPacket Packet) 27 | { 28 | switch (Packet.Type) 29 | { 30 | case SocketIOPacketType.CONNECT: 31 | OnConnect(); 32 | break; 33 | 34 | case SocketIOPacketType.DISCONNECT: 35 | Close(); 36 | break; 37 | 38 | case SocketIOPacketType.EVENT: 39 | OnEvent(Packet); 40 | break; 41 | 42 | case SocketIOPacketType.ACK: 43 | OnAck(Packet); 44 | break; 45 | 46 | case SocketIOPacketType.ERROR: 47 | OnError(Packet); 48 | break; 49 | 50 | case SocketIOPacketType.BINARY_EVENT: 51 | OnBinaryEvent(Packet); 52 | break; 53 | 54 | case SocketIOPacketType.BINARY_ACK: 55 | OnBinaryAck(Packet); 56 | break; 57 | 58 | default: 59 | OnEtc(Packet); 60 | break; 61 | } 62 | } 63 | 64 | private void OnConnect() 65 | { 66 | CallEventHandler(SocketIOEvent.CONNECTION); 67 | } 68 | 69 | protected void OnDisconnect(Exception Exception) 70 | { 71 | CallEventHandler(SocketIOEvent.DISCONNECT, new SocketIOException("Socket closed.", Exception).ToString()); 72 | 73 | AckManager.Dispose(); 74 | Reconstructor.Dispose(); 75 | } 76 | 77 | private void OnEvent(SocketIOPacket Packet) 78 | { 79 | CallHandler(Packet); 80 | } 81 | 82 | private void OnAck(SocketIOPacket Packet) 83 | { 84 | if (Packet?.JsonData != null) 85 | { 86 | AckManager.Invoke(Packet.ID, ((JArray)Packet.JsonData).ToArray()); 87 | } 88 | } 89 | 90 | private void OnError(SocketIOPacket Packet) 91 | { 92 | CallEventHandler(SocketIOEvent.ERROR, Packet?.JsonData?.ToString() ?? string.Empty); 93 | } 94 | 95 | private void OnBinaryEvent(SocketIOPacket Packet) 96 | { 97 | OnBinaryPacket(Packet); 98 | } 99 | 100 | private void OnBinaryAck(SocketIOPacket Packet) 101 | { 102 | OnBinaryPacket(Packet); 103 | } 104 | 105 | private void OnBinaryPacket(SocketIOPacket Packet) 106 | { 107 | if (Packet != null && Reconstructor.ConstructeeTokenCount == 0) 108 | { 109 | Reconstructor.SetPacket(Packet); 110 | } 111 | else 112 | { 113 | throw new SocketIOException(string.Format 114 | ( 115 | "Unexpected binary data: {0}. Reconstructor: {1}.", 116 | Packet, 117 | Reconstructor.OriginalPacket 118 | )); 119 | } 120 | } 121 | 122 | private void OnEtc(SocketIOPacket Packet) 123 | { 124 | if (Packet != null) 125 | { 126 | if (Reconstructor.ConstructeeTokenCount > 0) 127 | { 128 | SocketIOPacket ReconstructedPacket = Reconstructor.Reconstruct(Packet.RawData); 129 | 130 | if (Reconstructor.ConstructeeTokenCount == 0) 131 | { 132 | using (Reconstructor) 133 | { 134 | if (ReconstructedPacket.ID >= 0) 135 | { 136 | OnAck(ReconstructedPacket); 137 | } 138 | else 139 | { 140 | OnEvent(ReconstructedPacket); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Abstract/SocketIO.Emit.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using SocketIOSharp.Common.Packet; 3 | using System; 4 | 5 | namespace SocketIOSharp.Common.Abstract 6 | { 7 | partial class SocketIO 8 | { 9 | private object[] Arguments(params object[] Arguments) 10 | { 11 | int ArgumentsCount = Arguments.Length; 12 | 13 | if (Arguments[Arguments.Length - 1] == null) 14 | { 15 | ArgumentsCount--; 16 | } 17 | 18 | object[] Result = new object[ArgumentsCount]; 19 | 20 | for (int i = 0; i < ArgumentsCount; i++) 21 | { 22 | Result[i] = Arguments[i]; 23 | } 24 | 25 | return Result; 26 | } 27 | 28 | public TChildClass Emit(JToken Event, Action Callback = null) 29 | { 30 | return Emit(Event, Arguments(Callback)); 31 | } 32 | 33 | public TChildClass Emit(JToken Event, JToken Data, Action Callback = null) 34 | { 35 | return Emit(Event, Arguments(Data, Callback)); 36 | } 37 | 38 | public TChildClass Emit(JToken Event, params object[] Arguments) 39 | { 40 | if (Event != null) 41 | { 42 | JArray JsonArray = new JArray(); 43 | Action Callback = null; 44 | int ArgumentsCount = Arguments.Length; 45 | 46 | if (ArgumentsCount > 0 && Arguments[Arguments.Length - 1] is Action) 47 | { 48 | ArgumentsCount--; 49 | Callback = (Action)Arguments[Arguments.Length - 1]; 50 | } 51 | 52 | JsonArray.Add(Event); 53 | 54 | for (int i = 0; i < ArgumentsCount; i++) 55 | { 56 | JToken Data; 57 | 58 | try { Data = JToken.FromObject(Arguments[i]); } 59 | catch { Data = JValue.CreateNull(); } 60 | 61 | JsonArray.Add(Data); 62 | } 63 | 64 | Emit(SocketIOPacket.CreateEventPacket(JsonArray, AckManager.CreateAck(Callback))); 65 | } 66 | 67 | return this as TChildClass; 68 | } 69 | 70 | internal TChildClass Emit(SocketIOPacket Packet) 71 | { 72 | if (Packet != null) 73 | { 74 | object Encoded = Packet.Encode(); 75 | 76 | if (Packet.IsJson) 77 | { 78 | Emit((string)Encoded); 79 | } 80 | else 81 | { 82 | Emit((byte[])Encoded); 83 | } 84 | 85 | foreach (SocketIOPacket Attachment in Packet.Attachments) 86 | { 87 | Emit(Attachment); 88 | } 89 | } 90 | 91 | return this as TChildClass; 92 | } 93 | 94 | protected abstract TChildClass Emit(string Data); 95 | 96 | protected abstract TChildClass Emit(byte[] RawData); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Abstract/SocketIO.cs: -------------------------------------------------------------------------------- 1 | using SocketIOSharp.Common.Manager; 2 | using System; 3 | 4 | namespace SocketIOSharp.Common.Abstract 5 | { 6 | public abstract partial class SocketIO : IDisposable where TChildClass : SocketIO 7 | { 8 | protected SocketIOAckManager AckManager = new SocketIOAckManager() { AutoRemove = true }; 9 | 10 | protected SocketIO() 11 | { 12 | if (!(this is TChildClass)) 13 | { 14 | throw new ArgumentException(string.Format(@"'{0}' does not match with '{1}'.", GetType().Name, typeof(TChildClass).Name)); 15 | } 16 | } 17 | 18 | public abstract void Dispose(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Manager/SocketIOAckManager.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using SimpleThreadMonitor; 3 | using SocketIOSharp.Common.Packet; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Timers; 7 | 8 | namespace SocketIOSharp.Common.Manager 9 | { 10 | public class SocketIOAckManager 11 | { 12 | private readonly Timer AckTimer = new Timer() { AutoReset = true }; 13 | 14 | public bool UseAckTimeout { get; private set; } 15 | public const int MinTimeout = 10; 16 | private double TimeoutInMillis = 60 * 1000; 17 | 18 | private readonly List AckList = new List(); 19 | private readonly object AckMutex = new object(); 20 | 21 | public bool AutoRemove { get; set; } 22 | 23 | internal SocketIOAckManager() 24 | { 25 | SetTimeout(TimeoutInMillis); 26 | UseAckTimeout = false; 27 | 28 | AckTimer.Elapsed += (sender, e) => 29 | { 30 | SimpleMutex.Lock(AckMutex, () => 31 | { 32 | for (int i = 0; UseAckTimeout && i < AckList.Count; i++) 33 | { 34 | if (AckList[i] != null && DateTime.UtcNow.Subtract(AckList[i].RequestedTime).TotalMilliseconds > TimeoutInMillis) 35 | { 36 | AckList[i] = null; 37 | } 38 | } 39 | }); 40 | }; 41 | } 42 | 43 | public void Dispose() 44 | { 45 | StopTimer(); 46 | AckList.Clear(); 47 | } 48 | 49 | public void StartTimer() 50 | { 51 | if (!UseAckTimeout) 52 | { 53 | UseAckTimeout = true; 54 | AckTimer.Start(); 55 | } 56 | } 57 | 58 | public void StopTimer() 59 | { 60 | if (UseAckTimeout) 61 | { 62 | UseAckTimeout = false; 63 | AckTimer.Stop(); 64 | } 65 | } 66 | 67 | public void SetTimeout(double TimeoutInMillis) 68 | { 69 | if (TimeoutInMillis >= MinTimeout) 70 | { 71 | AckTimer.Interval = (this.TimeoutInMillis = TimeoutInMillis) / MinTimeout; 72 | } 73 | } 74 | 75 | public SocketIOAck CreateAck(Action Callback = null) 76 | { 77 | if (Callback != null) 78 | { 79 | SocketIOAck Result = null; 80 | 81 | SimpleMutex.Lock(AckMutex, () => 82 | { 83 | for (int i = 0; true; i++) 84 | { 85 | if (i < AckList.Count) 86 | { 87 | if (AckList[i] == null) 88 | { 89 | Result = AckList[i] = new SocketIOAck(i, Callback); 90 | break; 91 | } 92 | } 93 | else 94 | { 95 | SocketIOAck Ack = new SocketIOAck(AckList.Count, Callback); 96 | AckList.Add(Ack); 97 | 98 | Result = Ack; 99 | break; 100 | } 101 | } 102 | }); 103 | 104 | return Result; 105 | } 106 | else 107 | { 108 | return null; 109 | } 110 | } 111 | 112 | public void Invoke(int PacketID, params JToken[] Data) 113 | { 114 | SimpleMutex.Lock(AckMutex, () => 115 | { 116 | if (AckList.Count > PacketID && AckList[PacketID] != null) 117 | { 118 | AckList[PacketID].Invoke(Data); 119 | 120 | if (AutoRemove) 121 | { 122 | AckList[PacketID] = null; 123 | } 124 | } 125 | }); 126 | } 127 | 128 | public void Remove(int PacketID) 129 | { 130 | SimpleMutex.Lock(AckMutex, () => 131 | { 132 | if (AckList.Count > PacketID) 133 | { 134 | AckList[PacketID] = null; 135 | } 136 | }); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/Binary/Constructors/Constructor.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace SocketIOSharp.Common.Packet.Binary.Constructors 7 | { 8 | public abstract class Constructor : IDisposable 9 | { 10 | protected delegate bool Condition(JToken JsonData); 11 | 12 | protected static readonly string PLACEHOLDER = "_placeholder"; 13 | protected static readonly string NUM = "num"; 14 | 15 | public SocketIOPacket OriginalPacket { get; private set; } 16 | protected SocketIOPacket ConstructeePacket = null; 17 | 18 | protected Queue ConstructeeTokens = new Queue(); 19 | public int ConstructeeTokenCount { get { return ConstructeeTokens.Count; } } 20 | 21 | public void Dispose() 22 | { 23 | ConstructeeTokens.Clear(); 24 | } 25 | 26 | public virtual void SetPacket(SocketIOPacket ConstructeePacket) 27 | { 28 | if (ConstructeePacket != null) 29 | { 30 | this.ConstructeePacket = ConstructeePacket; 31 | OriginalPacket = ConstructeePacket.DeepClone(); 32 | } 33 | } 34 | 35 | protected void DFS(JToken JsonData, params Tuple[] ConditionActions) 36 | { 37 | if (JsonData != null) 38 | { 39 | if (ConditionActions != null) 40 | { 41 | foreach (Tuple ConditionAction in ConditionActions) 42 | { 43 | if (ConditionAction != null) 44 | { 45 | if (ConditionAction.Item1(JsonData)) 46 | { 47 | ConditionAction.Item2(JsonData); 48 | } 49 | } 50 | } 51 | } 52 | 53 | if (JsonData.HasValues) 54 | { 55 | for (JToken Child = JsonData.First; Child != null; Child = Child.Next) 56 | { 57 | DFS(Child, ConditionActions); 58 | } 59 | } 60 | } 61 | } 62 | 63 | protected JToken DequeueConstructeeTokenParent(out object ConstructeeTokenKey) 64 | { 65 | if (ConstructeeTokenCount > 0) 66 | { 67 | JToken ConstructeeToken = ConstructeeTokens.Dequeue(); 68 | JToken ConstructeeTokenParent = ConstructeeToken.Parent; 69 | 70 | while (ConstructeeTokenParent.Parent != null && ConstructeeTokenParent.Type == JTokenType.Property) 71 | { 72 | ConstructeeTokenParent = ConstructeeTokenParent.Parent; 73 | } 74 | 75 | string ConstructeeTokenPath = ConstructeeToken.Path; 76 | string ConstructeeTokenParentPath = ConstructeeTokenParent.Path; 77 | 78 | int ConstructeeTokenParentPathLength = ConstructeeTokenParentPath.Length; 79 | if (ConstructeeTokenParentPathLength > 0) 80 | { 81 | ConstructeeTokenParentPathLength++; 82 | } 83 | 84 | ConstructeeTokenParent = ConstructeePacket.JsonData.SelectToken(ConstructeeTokenParentPath); 85 | string ConstructeeTokenRelativePath = ConstructeeTokenPath.Substring(ConstructeeTokenParentPathLength); 86 | 87 | if (ConstructeeTokenRelativePath.StartsWith("[") && ConstructeeTokenRelativePath.EndsWith("]")) 88 | { 89 | ConstructeeTokenRelativePath = ConstructeeTokenRelativePath.Substring(1).Substring(0, ConstructeeTokenRelativePath.Length - 2); 90 | } 91 | 92 | if (ConstructeeTokenParent.Type == JTokenType.Array) 93 | { 94 | ConstructeeTokenKey = int.Parse(ConstructeeTokenRelativePath); 95 | } 96 | else if (ConstructeeTokenParent.Type == JTokenType.Object) 97 | { 98 | ConstructeeTokenKey = ConstructeeTokenRelativePath; 99 | } 100 | else 101 | { 102 | throw new SocketIOException("Invalid placeholder parent type: " + ConstructeeTokenParent.Type); 103 | } 104 | 105 | return ConstructeeTokenParent; 106 | } 107 | else 108 | { 109 | return (JToken)(ConstructeeTokenKey = null); 110 | } 111 | } 112 | 113 | protected bool IsPlaceholder(JToken JsonData) 114 | { 115 | return (JsonData.Type == JTokenType.Object && JsonData.Count() == 2) && 116 | (JsonData.First.Type == JTokenType.Property && JsonData.Last.Type == JTokenType.Property) && 117 | (JsonData.First.First.Type == JTokenType.Boolean && JsonData.Last.First.Type == JTokenType.Integer) && 118 | (JsonData.First.First.Path.Substring(JsonData.First.First.Path.LastIndexOf('.') + 1).Equals(PLACEHOLDER)) && 119 | (JsonData.Last.First.Path.Substring(JsonData.Last.First.Path.LastIndexOf('.') + 1).Equals(NUM)); 120 | } 121 | 122 | protected bool IsBytes(JToken JsonData) 123 | { 124 | return JsonData.Type == JTokenType.Bytes; 125 | } 126 | 127 | public override string ToString() 128 | { 129 | return string.Format 130 | ( 131 | "Packet={0}, OriginalPacket={1}, TokenQueue.Count={2}", 132 | ConstructeePacket, 133 | OriginalPacket, 134 | ConstructeeTokens.Count 135 | ); 136 | } 137 | 138 | protected delegate void ConstructorAction(JToken Data); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/Binary/Constructors/Deconstructor.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | 4 | namespace SocketIOSharp.Common.Packet.Binary.Constructors 5 | { 6 | public class Deconstructor : Constructor 7 | { 8 | private int PlaceholderCount = 0; 9 | 10 | internal Deconstructor() 11 | { 12 | 13 | } 14 | 15 | public override void SetPacket(SocketIOPacket ConstructeePacket) 16 | { 17 | if (ConstructeePacket != null) 18 | { 19 | base.SetPacket(ConstructeePacket); 20 | 21 | ConstructorAction EnqueueAction = new ConstructorAction((Data) => ConstructeeTokens.Enqueue(Data)); 22 | ConstructorAction CountAction = new ConstructorAction((Data) => PlaceholderCount++); 23 | 24 | Tuple[] ConditionalActions = new Tuple[] 25 | { 26 | new Tuple(IsBytes, EnqueueAction), 27 | new Tuple(IsPlaceholder, CountAction) 28 | }; 29 | 30 | DFS(ConstructeePacket.JsonData, ConditionalActions); 31 | 32 | if (PlaceholderCount > 0) 33 | { 34 | throw new SocketIOException("Bytes token count is not match to placeholder count. " + this); 35 | } 36 | } 37 | } 38 | 39 | public SocketIOPacket Deconstruct() 40 | { 41 | int PlaceholderIndex = 0; 42 | 43 | while (ConstructeeTokenCount > 0) 44 | { 45 | JToken Parent = DequeueConstructeeTokenParent(out object Key); 46 | ConstructeePacket.Attachments.Enqueue(SocketIOPacket.Decode((byte[])Parent[Key])); 47 | 48 | Parent[Key] = new JObject 49 | { 50 | [PLACEHOLDER] = true, 51 | [NUM] = PlaceholderIndex++ 52 | }; 53 | } 54 | 55 | return ConstructeePacket; 56 | } 57 | 58 | public override string ToString() 59 | { 60 | return string.Format("Deconstructor: {0}, PlaceholderCount={1}", base.ToString(), PlaceholderCount); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/Binary/Constructors/Reconstructor.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | 4 | namespace SocketIOSharp.Common.Packet.Binary.Constructors 5 | { 6 | public class Reconstructor : Constructor 7 | { 8 | internal Reconstructor() 9 | { 10 | 11 | } 12 | 13 | public override void SetPacket(SocketIOPacket ConstructeePacket) 14 | { 15 | if (ConstructeePacket != null) 16 | { 17 | base.SetPacket(ConstructeePacket); 18 | 19 | ConstructorAction EnqueueAction = new ConstructorAction((Data) => ConstructeeTokens.Enqueue(Data)); 20 | Tuple[] ConditionalActions = new Tuple[] 21 | { 22 | new Tuple(IsPlaceholder, EnqueueAction), 23 | }; 24 | 25 | DFS(ConstructeePacket.JsonData, ConditionalActions); 26 | 27 | if (ConstructeePacket.Attachments.Count != ConstructeeTokenCount) 28 | { 29 | throw new SocketIOException("Attachment count is not match to placeholder count. " + this); 30 | } 31 | } 32 | } 33 | 34 | public SocketIOPacket Reconstruct(byte[] BinaryData) 35 | { 36 | if (ConstructeeTokenCount > 0) 37 | { 38 | JToken Parent = base.DequeueConstructeeTokenParent(out object Key); 39 | ConstructeePacket.Attachments.Dequeue(); 40 | 41 | Parent[Key] = BinaryData; 42 | } 43 | 44 | if (ConstructeeTokenCount == 0) 45 | { 46 | return ConstructeePacket; 47 | } 48 | else 49 | { 50 | return null; 51 | } 52 | } 53 | 54 | public override string ToString() 55 | { 56 | return string.Format("Reconstructor: {0}", base.ToString()); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOAck.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | 4 | namespace SocketIOSharp.Common.Packet 5 | { 6 | public class SocketIOAck 7 | { 8 | public DateTime RequestedTime { get; private set; } 9 | 10 | public int PacketID { get; private set; } 11 | public Action Callback { get; private set; } 12 | 13 | internal SocketIOAck(int PacketID, Action Callback = null) 14 | { 15 | RequestedTime = DateTime.UtcNow; 16 | 17 | this.PacketID = PacketID; 18 | this.Callback = Callback; 19 | } 20 | 21 | public void Invoke(params JToken[] Data) 22 | { 23 | Callback(Data); 24 | } 25 | 26 | public override string ToString() 27 | { 28 | return string.Format 29 | ( 30 | "[Ack: PacketID={0}, RequestedTime={1}, Action={2}]", 31 | PacketID, 32 | RequestedTime, 33 | Callback 34 | ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOAckEvent.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | 4 | namespace SocketIOSharp.Common.Packet 5 | { 6 | public class SocketIOAckEvent 7 | { 8 | public JToken[] Data { get; private set; } 9 | public Action Callback { get; private set; } 10 | 11 | internal SocketIOAckEvent(JToken[] Data, Action Callback) 12 | { 13 | this.Data = Data; 14 | this.Callback = Callback; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOPacket.Static/SocketIOPacket.Decoder.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Common.Packet; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace SocketIOSharp.Common.Packet 9 | { 10 | partial class SocketIOPacket 11 | { 12 | internal static SocketIOPacket Decode(EngineIOPacket EngineIOPacket) 13 | { 14 | if ((EngineIOPacket?.Type ?? EngineIOPacketType.UNKNOWN) == EngineIOPacketType.MESSAGE) 15 | { 16 | try 17 | { 18 | if (EngineIOPacket.IsText) 19 | { 20 | return Decode(EngineIOPacket.Data); 21 | } 22 | else 23 | { 24 | return Decode(EngineIOPacket.RawData); 25 | } 26 | } 27 | catch (Exception Exception) 28 | { 29 | throw new SocketIOException("Packet decoding failed. " + EngineIOPacket, Exception); 30 | } 31 | } 32 | else 33 | { 34 | throw new SocketIOException("Type of Engine.IO packet is not message."); 35 | } 36 | } 37 | 38 | internal static SocketIOPacket Decode(string Data) 39 | { 40 | SocketIOPacket Packet = new SocketIOPacket(); 41 | int Offset = 0; 42 | 43 | Packet.Type = (SocketIOPacketType)(Data[Offset] - '0'); 44 | 45 | if (Data.Length > 1) 46 | { 47 | if (Packet.Type == SocketIOPacketType.BINARY_EVENT || Packet.Type == SocketIOPacketType.BINARY_ACK) 48 | { 49 | StringBuilder Builder = new StringBuilder(); 50 | 51 | while (Offset < Data.Length - 1) 52 | { 53 | char c = Data[++Offset]; 54 | 55 | if (char.IsNumber(c)) 56 | { 57 | Builder.Append(c); 58 | } 59 | else 60 | { 61 | break; 62 | } 63 | } 64 | 65 | Packet.Attachments = new Queue(new SocketIOPacket[int.Parse(Builder.ToString())]); 66 | } 67 | 68 | if ('/' == Data[Offset + 1]) 69 | { 70 | StringBuilder Builder = new StringBuilder(); 71 | 72 | while (Offset < Data.Length - 1 && Data[++Offset] != ',') 73 | { 74 | Builder.Append(Data[Offset]); 75 | } 76 | 77 | Packet.Namespace = Builder.ToString(); 78 | } 79 | else 80 | { 81 | Packet.Namespace = "/"; 82 | } 83 | 84 | char Next = Data[Offset + 1]; 85 | 86 | if (!char.IsWhiteSpace(Next) && char.IsNumber(Next)) 87 | { 88 | StringBuilder Builder = new StringBuilder(); 89 | 90 | while (Offset < Data.Length - 1) 91 | { 92 | char c = Data[++Offset]; 93 | 94 | if (char.IsNumber(c)) 95 | { 96 | Builder.Append(c); 97 | } 98 | else 99 | { 100 | --Offset; 101 | break; 102 | } 103 | } 104 | 105 | Packet.ID = int.Parse(Builder.ToString()); 106 | } 107 | 108 | if (++Offset < Data.Length - 1) 109 | { 110 | Packet.JsonData = (JToken)JsonConvert.DeserializeObject(Data.Substring(Offset)); 111 | Packet.IsJson = true; 112 | } 113 | } 114 | 115 | return Packet; 116 | } 117 | 118 | internal static SocketIOPacket Decode(byte[] RawData) 119 | { 120 | return new SocketIOPacket() 121 | { 122 | RawData = RawData, 123 | IsJson = false, 124 | IsBinary = true 125 | }; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOPacket.Static/SocketIOPacket.Factory.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using SocketIOSharp.Common.Packet.Binary.Constructors; 3 | 4 | namespace SocketIOSharp.Common.Packet 5 | { 6 | partial class SocketIOPacket 7 | { 8 | internal static SocketIOPacket CreateConnectionPacket() 9 | { 10 | return new SocketIOPacket() 11 | { 12 | Type = SocketIOPacketType.CONNECT, 13 | IsJson = true 14 | }; 15 | } 16 | 17 | internal static SocketIOPacket CreateEventPacket(JArray JsonArray, SocketIOAck Ack) 18 | { 19 | SocketIOPacket Packet = CreateMessagePacket(JsonArray, Ack); 20 | 21 | if (Packet.IsJson) 22 | { 23 | Packet.Type = SocketIOPacketType.EVENT; 24 | } 25 | else 26 | { 27 | Packet.Type = SocketIOPacketType.BINARY_EVENT; 28 | } 29 | 30 | Packet.IsJson = true; 31 | return Packet; 32 | } 33 | 34 | internal static SocketIOPacket CreateAckPacket(JArray JsonArray, int PacketID) 35 | { 36 | if (PacketID >= 0) 37 | { 38 | SocketIOPacket Packet = CreateMessagePacket(JsonArray, PacketID); 39 | 40 | if (Packet.IsJson) 41 | { 42 | Packet.Type = SocketIOPacketType.ACK; 43 | } 44 | else 45 | { 46 | Packet.Type = SocketIOPacketType.BINARY_ACK; 47 | } 48 | 49 | Packet.IsJson = true; 50 | return Packet; 51 | } 52 | else 53 | { 54 | return null; 55 | } 56 | } 57 | 58 | private static SocketIOPacket CreateMessagePacket(JArray JsonArray, SocketIOAck Ack) 59 | { 60 | return CreateMessagePacket(JsonArray, Ack == null ? -1 : Ack.PacketID); 61 | } 62 | 63 | private static SocketIOPacket CreateMessagePacket(JArray JsonArray, int PacketID) 64 | { 65 | SocketIOPacket Packet = new SocketIOPacket 66 | { 67 | JsonData = JsonArray, 68 | IsJson = true 69 | }; 70 | 71 | if (PacketID >= 0) 72 | { 73 | Packet.ID = PacketID; 74 | } 75 | 76 | using (Deconstructor Deconstructor = new Deconstructor()) 77 | { 78 | Deconstructor.SetPacket(Packet); 79 | Packet = Deconstructor.Deconstruct(); 80 | 81 | if (Packet.Attachments.Count > 0) 82 | { 83 | Packet.IsJson = false; 84 | } 85 | } 86 | 87 | return Packet; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOPacket.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace SocketIOSharp.Common.Packet 8 | { 9 | public partial class SocketIOPacket 10 | { 11 | public SocketIOPacketType Type { get; private set; } 12 | 13 | public Queue Attachments { get; private set; } 14 | public string Namespace { get; private set; } 15 | public int ID { get; private set; } 16 | 17 | public bool IsJson { get; private set; } 18 | public bool IsBinary { get; private set; } 19 | 20 | public JToken JsonData { get; set; } 21 | public byte[] RawData { get; private set; } 22 | 23 | private SocketIOPacket() 24 | { 25 | Type = SocketIOPacketType.UNKNOWN; 26 | 27 | Attachments = new Queue(); 28 | Namespace = "/"; 29 | ID = -1; 30 | 31 | IsJson = false; 32 | IsBinary = false; 33 | 34 | JsonData = null; 35 | RawData = null; 36 | } 37 | 38 | private SocketIOPacket(SocketIOPacket Packet) 39 | { 40 | Type = Packet.Type; 41 | 42 | if (Packet.Attachments != null) 43 | { 44 | Attachments = new Queue(Packet.Attachments); 45 | } 46 | else 47 | { 48 | Attachments = null; 49 | } 50 | 51 | Namespace = Packet.Namespace; 52 | ID = Packet.ID; 53 | 54 | IsJson = Packet.IsJson; 55 | IsBinary = Packet.IsBinary; 56 | 57 | if (Packet.JsonData != null) 58 | { 59 | JsonData = Packet.JsonData.DeepClone(); 60 | } 61 | else 62 | { 63 | JsonData = null; 64 | } 65 | 66 | if (Packet.RawData != null) 67 | { 68 | RawData = new List(Packet.RawData).ToArray(); 69 | } 70 | else 71 | { 72 | RawData = null; 73 | } 74 | } 75 | 76 | public SocketIOPacket DeepClone() 77 | { 78 | return new SocketIOPacket(this); 79 | } 80 | 81 | public override string ToString() 82 | { 83 | StringBuilder Builder = new StringBuilder(string.Format 84 | ( 85 | "Packet: SocketPacketType={0}, ", 86 | Type 87 | )); 88 | 89 | if (Attachments != null && Attachments.Count > 0) 90 | { 91 | Builder.Append("Attachments=["); 92 | 93 | foreach (SocketIOPacket Attachment in Attachments) 94 | { 95 | Builder.Append(Attachment.ToString()); 96 | } 97 | 98 | Builder.Append("], "); 99 | } 100 | 101 | Builder.Append(string.Format("Namespace={0}, ID={1}", Namespace, ID)); 102 | 103 | if (JsonData != null) 104 | { 105 | Builder.Append(string.Format(", JsonData={0}", JsonData)); 106 | } 107 | 108 | if (RawData != null) 109 | { 110 | Builder.Append(string.Format(", BinaryData={0}", BitConverter.ToString(RawData))); 111 | } 112 | 113 | return Builder.ToString(); 114 | } 115 | 116 | internal object Encode() 117 | { 118 | try 119 | { 120 | if (IsJson) 121 | { 122 | StringBuilder Builder = new StringBuilder(); 123 | 124 | if (Type != SocketIOPacketType.UNKNOWN) 125 | { 126 | Builder.Append((int)Type); 127 | } 128 | 129 | if (Type == SocketIOPacketType.BINARY_EVENT || Type == SocketIOPacketType.BINARY_ACK) 130 | { 131 | Builder.Append(Attachments.Count); 132 | Builder.Append('-'); 133 | } 134 | 135 | if (!string.IsNullOrEmpty(Namespace) && !Namespace.Equals("/")) 136 | { 137 | Builder.Append(Namespace); 138 | Builder.Append(','); 139 | } 140 | 141 | if (ID > -1) 142 | { 143 | Builder.Append(ID); 144 | } 145 | 146 | return Builder.Append(JsonData?.ToString(Formatting.None) ?? string.Empty).ToString(); 147 | } 148 | else 149 | { 150 | if (Type != SocketIOPacketType.UNKNOWN) 151 | { 152 | List Buffer = new List() { (byte)Type }; 153 | Buffer.AddRange(RawData); 154 | 155 | return Buffer.ToArray(); 156 | } 157 | else 158 | { 159 | return RawData; 160 | } 161 | } 162 | } 163 | catch (Exception Exception) 164 | { 165 | throw new SocketIOException("Packet encoding failed. " + this, Exception); 166 | } 167 | } 168 | } 169 | } -------------------------------------------------------------------------------- /SocketIOSharp/Common/Packet/SocketIOPacketType.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Common.Packet 2 | { 3 | public enum SocketIOPacketType 4 | { 5 | UNKNOWN = -1, 6 | CONNECT = 0, 7 | DISCONNECT = 1, 8 | EVENT = 2, 9 | ACK = 3, 10 | ERROR = 4, 11 | BINARY_EVENT = 5, 12 | BINARY_ACK = 6, 13 | CONTROL = 7, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/SocketIOEvent.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Common 2 | { 3 | public static class SocketIOEvent 4 | { 5 | public static readonly string CONNECTION = "connection"; 6 | public static readonly string DISCONNECT = "disconnect"; 7 | public static readonly string ERROR = "error"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SocketIOSharp/Common/SocketIOException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SocketIOSharp.Common 4 | { 5 | internal class SocketIOException : Exception 6 | { 7 | internal SocketIOException(string message) : base(message) 8 | { 9 | } 10 | 11 | internal SocketIOException(string message, Exception innerException) : base(message, innerException) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SocketIOSharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 어셈블리의 일반 정보는 다음 특성 집합을 통해 제어됩니다. 6 | // 어셈블리와 관련된 정보를 수정하려면 7 | // 이 특성 값을 변경하십시오. 8 | 9 | // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 10 | // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면 11 | // 해당 형식에 대해 ComVisible 특성을 true로 설정하십시오. 12 | [assembly: ComVisible(false)] 13 | 14 | // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. 15 | [assembly: Guid("ed33e59a-0a10-43d0-95bb-61d603dd871c")] 16 | 17 | // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. 18 | // 19 | // 주 버전 20 | // 부 버전 21 | // 빌드 번호 22 | // 수정 버전 23 | // 24 | // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 버전이 자동으로 25 | // 지정되도록 할 수 있습니다. 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/Client/SocketIOSocket.Send.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Server.Client 2 | { 3 | partial class SocketIOSocket 4 | { 5 | protected override SocketIOSocket Emit(string Data) 6 | { 7 | Socket.Send(Data); 8 | 9 | return this; 10 | } 11 | 12 | protected override SocketIOSocket Emit(byte[] RawData) 13 | { 14 | Socket.Send(RawData); 15 | 16 | return this; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/Client/SocketIOSocket.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Common.Enum; 2 | using EngineIOSharp.Server.Client; 3 | using SocketIOSharp.Common.Abstract.Connection; 4 | 5 | namespace SocketIOSharp.Server.Client 6 | { 7 | public partial class SocketIOSocket : SocketIOConnection 8 | { 9 | private readonly EngineIOSocket Socket; 10 | 11 | public SocketIOServer Server { get; private set; } 12 | 13 | public override EngineIOReadyState ReadyState => Socket.ReadyState; 14 | 15 | internal SocketIOSocket(EngineIOSocket Socket, SocketIOServer Server) 16 | { 17 | AckManager.SetTimeout(Server.Option.PingTimeout); 18 | 19 | Socket.OnMessage(OnPacket); 20 | Socket.OnClose((message, description) => OnDisconnect(description)); 21 | 22 | this.Server = Server; 23 | this.Socket = Socket; 24 | } 25 | 26 | public override SocketIOSocket Close() 27 | { 28 | Socket.Close(); 29 | 30 | return this; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/SocketIOServer.Emit.cs: -------------------------------------------------------------------------------- 1 | namespace SocketIOSharp.Server 2 | { 3 | partial class SocketIOServer 4 | { 5 | protected override SocketIOServer Emit(string Data) 6 | { 7 | Server.Broadcast(Data); 8 | 9 | return this; 10 | } 11 | 12 | protected override SocketIOServer Emit(byte[] RawData) 13 | { 14 | Server.Broadcast(RawData); 15 | 16 | return this; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/SocketIOServer.Event.cs: -------------------------------------------------------------------------------- 1 | using EmitterSharp; 2 | using Newtonsoft.Json.Linq; 3 | using SimpleThreadMonitor; 4 | using SocketIOSharp.Common; 5 | using SocketIOSharp.Server.Client; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace SocketIOSharp.Server 10 | { 11 | partial class SocketIOServer 12 | { 13 | private readonly SocketIOConnectionHandler ConnectionHandlerManager = new SocketIOConnectionHandler(); 14 | 15 | public SocketIOServer OnConnection(Action Callback) 16 | { 17 | ConnectionHandlerManager.On(SocketIOEvent.CONNECTION, Callback); 18 | 19 | return this; 20 | } 21 | 22 | private class SocketIOConnectionHandler : Emitter 23 | { 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/SocketIOServer.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Server; 2 | using EngineIOSharp.Server.Client; 3 | using SimpleThreadMonitor; 4 | using SocketIOSharp.Common; 5 | using SocketIOSharp.Common.Abstract; 6 | using SocketIOSharp.Common.Packet; 7 | using SocketIOSharp.Server.Client; 8 | using System.Collections.Generic; 9 | 10 | namespace SocketIOSharp.Server 11 | { 12 | public partial class SocketIOServer : SocketIO 13 | { 14 | private readonly EngineIOServer Server; 15 | 16 | private readonly List _Clients = new List(); 17 | private readonly object ClientMutex = new object(); 18 | 19 | public List Clients { get { return new List(_Clients); } } 20 | public int ClientsCounts { get { return _Clients.Count; } } 21 | 22 | public SocketIOServerOption Option { get; private set; } 23 | 24 | public SocketIOServer(SocketIOServerOption Option) 25 | { 26 | Server = new EngineIOServer(this.Option = Option); 27 | Server.OnConnection(OnConnection); 28 | 29 | AckManager.SetTimeout(Option.PingTimeout); 30 | } 31 | 32 | public SocketIOServer Start() 33 | { 34 | Server.Start(); 35 | 36 | return this; 37 | } 38 | 39 | public SocketIOServer Stop() 40 | { 41 | Server.Stop(); 42 | 43 | return this; 44 | } 45 | 46 | public override void Dispose() 47 | { 48 | Stop(); 49 | } 50 | 51 | private void OnConnection(EngineIOSocket EngineIOSocket) 52 | { 53 | SocketIOSocket Socket = new SocketIOSocket(EngineIOSocket, this); 54 | 55 | SimpleMutex.Lock(ClientMutex, () => 56 | { 57 | _Clients.Add(Socket); 58 | 59 | Socket.On(SocketIOEvent.DISCONNECT, () => 60 | { 61 | SimpleMutex.Lock(ClientMutex, () => 62 | { 63 | _Clients.Remove(Socket); 64 | }); 65 | }); 66 | 67 | Socket.Emit(SocketIOPacket.CreateConnectionPacket()); 68 | ConnectionHandlerManager.Emit(SocketIOEvent.CONNECTION, Socket); 69 | }); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /SocketIOSharp/Server/SocketIOServerOption.cs: -------------------------------------------------------------------------------- 1 | using EngineIOSharp.Common; 2 | using EngineIOSharp.Server; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Security; 6 | using System.Security.Cryptography.X509Certificates; 7 | using WebSocketSharp.Net; 8 | using WebSocketSharp.Net.WebSockets; 9 | 10 | namespace SocketIOSharp.Server 11 | { 12 | public class SocketIOServerOption : EngineIOServerOption 13 | { 14 | /// 15 | /// Options for Socket.IO server. 16 | /// 17 | /// Port to listen. 18 | /// Path to listen. 19 | /// Whether to secure connections. 20 | /// How many ms without a pong packet to consider the connection closed. 21 | /// How many ms before sending a new ping packet. 22 | /// How many ms before an uncompleted transport upgrade is cancelled. 23 | /// Whether to accept polling transport. 24 | /// Whether to accept websocket transport. 25 | /// Whether to allow transport upgrade. 26 | /// Whether to use cookie. 27 | /// Name of sid cookie. 28 | /// Configuration of the cookie that contains the client sid to send as part of handshake response headers. This cookie might be used for sticky-session. 29 | /// A function that receives a given handshake or upgrade http request as its first parameter, and can decide whether to continue or not. 30 | /// A function that receives a given handshake or upgrade websocket connection as its first parameter, and can decide whether to continue or not. 31 | /// An optional packet which will be concatenated to the handshake packet emitted by Engine.IO. 32 | /// The certificate used to authenticate the server. 33 | /// Callback used to validate the certificate supplied by the client. 34 | public SocketIOServerOption(ushort Port, string Path = "/socket.io", bool Secure = false, ulong PingTimeout = 5000, ulong PingInterval = 25000, ulong UpgradeTimeout = 10000, bool Polling = true, bool WebSocket = true, bool AllowUpgrade = true, bool SetCookie = true, string SIDCookieName = "io", IDictionary Cookies = null, Action> AllowHttpRequest = null, Action> AllowWebSocket = null, object InitialData = null, X509Certificate2 ServerCertificate = null, RemoteCertificateValidationCallback ClientCertificateValidationCallback = null) : base(Port, Path, Secure, PingTimeout, PingInterval, UpgradeTimeout, Polling, WebSocket, AllowUpgrade, SetCookie, SIDCookieName, Cookies, AllowHttpRequest, AllowWebSocket, InitialData, ServerCertificate, ClientCertificateValidationCallback) 35 | { 36 | 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SocketIOSharp/SocketIOSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net45;net40;netstandard2.0 5 | $(LibraryFrameworks) 6 | SocketIOSharp 7 | SocketIOSharp 8 | 512 9 | uhm0311 10 | uhm0311 11 | Socket.IO 12 | Copyright (c) 2016-2020 uhm0311 13 | C# implementation of Socket.IO protocol client. 14 | SocketIOSharp 15 | Socket.IO;SocketIO 16 | https://github.com/uhm0311/SocketIOSharp 17 | MIT 18 | false 19 | git 20 | https://github.com/uhm0311/SocketIOSharp.git 21 | icon.png 22 | 2.12 23 | 2.0.3 24 | Update EngineIOSharp dependency. 25 | ../nuget 26 | true 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /SocketIOSharp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhm0311/SocketIOSharp/6df5c61ff8180522bb6316444c485ff7306e3a9b/icon.png --------------------------------------------------------------------------------