├── .appveyor.yml ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── addon_config.mk ├── docs ├── Doxyfile └── screen.png ├── example ├── addons.make ├── bin │ └── data │ │ ├── DocumentRoot │ │ ├── 404.html │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.min.css │ │ │ ├── font-awesome.css │ │ │ ├── font-awesome.min.css │ │ │ ├── prism.css │ │ │ └── style.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ ├── img │ │ │ ├── favicon.ico │ │ │ └── openFrameworks.png │ │ ├── index.html │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── jquery.json.js │ │ │ ├── jquery.jsonrpcclient.js │ │ │ ├── jquery.min.js │ │ │ ├── jquery.min.map │ │ │ ├── main.js │ │ │ ├── ofxHTTP.js │ │ │ ├── ofxUtils.js │ │ │ └── prism.js │ │ └── media │ │ ├── ipsum.txt │ │ ├── ping.wav │ │ └── pong.wav └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example_no_window ├── addons.make ├── bin │ └── data │ │ ├── DocumentRoot │ │ ├── 404.html │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.min.css │ │ │ ├── font-awesome.css │ │ │ ├── font-awesome.min.css │ │ │ ├── prism.css │ │ │ └── style.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ ├── img │ │ │ ├── favicon.ico │ │ │ └── openFrameworks.png │ │ ├── index.html │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── jquery.json.js │ │ │ ├── jquery.jsonrpcclient.js │ │ │ ├── jquery.min.js │ │ │ ├── jquery.min.map │ │ │ ├── main.js │ │ │ ├── ofxHTTP.js │ │ │ ├── ofxUtils.js │ │ │ └── prism.js │ │ └── media │ │ └── ipsum.txt └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── libs ├── ofxHTTP │ ├── include │ │ └── ofx │ │ │ └── HTTP │ │ │ └── JSONRPCServer.h │ └── src │ │ └── JSONRPCServer.cpp └── ofxJSONRPC │ ├── include │ └── ofx │ │ └── JSONRPC │ │ ├── BaseMessage.h │ │ ├── Error.h │ │ ├── Errors.h │ │ ├── JSONRPC.h │ │ ├── JSONRPCUtils.h │ │ ├── Method.h │ │ ├── MethodArgs.h │ │ ├── MethodRegistry.h │ │ ├── Request.h │ │ └── Response.h │ └── src │ ├── BaseMessage.cpp │ ├── Error.cpp │ ├── Errors.cpp │ ├── JSONRPCUtils.cpp │ ├── MethodArgs.cpp │ ├── MethodRegistry.cpp │ ├── Request.cpp │ └── Response.cpp ├── ofxaddons_thumbnail.png └── src └── ofxJSONRPC.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: Visual Studio 2015 RC 3 | 4 | environment: 5 | global: 6 | APPVEYOR_OS_NAME: windows 7 | matrix: 8 | #MSYS2 Building 9 | - platform: x86 10 | BUILDER: MSYS2 11 | 12 | #VisualStudio Building 13 | - platform: x86 14 | BUILDER : VS 15 | BITS: 32 16 | - platform: x64 17 | BUILDER : VS 18 | BITS: 64 19 | 20 | configuration: Debug 21 | shallow_clone: true 22 | clone_depth: 10 23 | init: 24 | - set MAKEFLAGS=-s 25 | - set MSYS2_PATH=c:\msys64 26 | - set CHERE_INVOKING=1 27 | - if "%BUILDER%_%PLATFORM%"=="MSYS2_x86" set MSYSTEM=MINGW32 28 | - if "%BUILDER%_%PLATFORM%"=="MSYS2_x64" set MSYSTEM=MINGW64 29 | - if "%BUILDER%"=="VS" set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% 30 | - cd %APPVEYOR_BUILD_FOLDER%\..\ 31 | - set OF_ROOT=%CD%\openFrameworks 32 | - set OF_ADDON_NAME=%APPVEYOR_PROJECT_NAME% 33 | install: 34 | - git clone --depth=1 --branch=CI-TESTS https://github.com/bakercp/openFrameworks %OF_ROOT% 35 | - cd %OF_ROOT% 36 | - call scripts\ci\addons\install.cmd 37 | build_script: 38 | - cd %OF_ROOT% 39 | - call scripts\ci\addons\build.cmd 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/html 2 | docs/tagfile.xml 3 | 4 | raw 5 | *.plist 6 | *.xcconfig 7 | *.xcodeproj 8 | 9 | *.mode1v3 10 | 11 | # xcode 12 | *.pbxuser 13 | *.perspectivev3 14 | xcuserdata 15 | build 16 | *.app 17 | #*.a 18 | 19 | # OSX 20 | .DS_Store 21 | .AppleDouble 22 | 23 | # codeblocks 24 | *.layout 25 | example/obj 26 | 27 | # Win 28 | *.exe 29 | *.dll 30 | ## Ignore Visual Studio temporary files, build results, and 31 | ## files generated by popular Visual Studio add-ons. 32 | 33 | # User-specific files 34 | *.suo 35 | *.user 36 | *.sln.docstates 37 | 38 | # Build results 39 | 40 | [Dd]ebug/ 41 | [Rr]elease/ 42 | x64/ 43 | build/ 44 | [Bb]in/ 45 | [Oo]bj/ 46 | 47 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 48 | !packages/*/build/ 49 | 50 | # MSTest test Results 51 | [Tt]est[Rr]esult*/ 52 | [Bb]uild[Ll]og.* 53 | 54 | *_i.c 55 | *_p.c 56 | *.ilk 57 | *.meta 58 | *.obj 59 | *.pch 60 | *.pdb 61 | *.pgc 62 | *.pgd 63 | *.rsp 64 | *.sbr 65 | *.tlb 66 | *.tli 67 | *.tlh 68 | *.tmp 69 | *.tmp_proj 70 | *.log 71 | *.vspscc 72 | *.vssscc 73 | .builds 74 | *.pidb 75 | *.log 76 | *.scc 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | 91 | # Guidance Automation Toolkit 92 | *.gpState 93 | 94 | # ReSharper is a .NET coding add-in 95 | _ReSharper*/ 96 | *.[Rr]e[Ss]harper 97 | 98 | # TeamCity is a build add-in 99 | _TeamCity* 100 | 101 | # DotCover is a Code Coverage Tool 102 | *.dotCover 103 | 104 | # NCrunch 105 | *.ncrunch* 106 | .*crunch*.local.xml 107 | 108 | # Installshield output folder 109 | [Ee]xpress/ 110 | 111 | # DocProject is a documentation generator add-in 112 | DocProject/buildhelp/ 113 | DocProject/Help/*.HxT 114 | DocProject/Help/*.HxC 115 | DocProject/Help/*.hhc 116 | DocProject/Help/*.hhk 117 | DocProject/Help/*.hhp 118 | DocProject/Help/Html2 119 | DocProject/Help/html 120 | 121 | # Click-Once directory 122 | publish/ 123 | 124 | # Publish Web Output 125 | *.Publish.xml 126 | *.pubxml 127 | 128 | # NuGet Packages Directory 129 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 130 | #packages/ 131 | 132 | # Windows Azure Build Output 133 | csx 134 | *.build.csdef 135 | 136 | # Windows Store app package directory 137 | AppPackages/ 138 | 139 | # Others 140 | sql/ 141 | *.Cache 142 | ClientBin/ 143 | [Ss]tyle[Cc]op.* 144 | ~$* 145 | *~ 146 | *.dbmdl 147 | *.[Pp]ublish.xml 148 | *.pfx 149 | *.publishsettings 150 | 151 | # RIA/Silverlight projects 152 | Generated_Code/ 153 | 154 | # Backup & report files from converting an old project file to a newer 155 | # Visual Studio version. Backup files are not needed, because we have git ;-) 156 | _UpgradeReport_Files/ 157 | Backup*/ 158 | UpgradeLog*.XML 159 | UpgradeLog*.htm 160 | 161 | # SQL Server files 162 | App_Data/*.mdf 163 | App_Data/*.ldf 164 | 165 | # ========================= 166 | # Windows detritus 167 | # ========================= 168 | 169 | # Windows image file caches 170 | Thumbs.db 171 | ehthumbs.db 172 | 173 | # Folder config file 174 | Desktop.ini 175 | 176 | # Recycle Bin used on file shares 177 | $RECYCLE.BIN/ 178 | 179 | # Mac crap 180 | .DS_Store 181 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | compiler: gcc 3 | sudo: true 4 | matrix: 5 | include: 6 | # fully specify builds, include can't dynamically expand matrix entries 7 | # relative order of sudo and env is important so that addons: is recognized 8 | 9 | # Linux 64bit, OF master 10 | - os: linux 11 | dist: trusty 12 | sudo: required 13 | env: TARGET="linux64" OF_BRANCH="master" 14 | addons: 15 | apt: 16 | sources: 17 | - ubuntu-toolchain-r-test 18 | packages: 19 | - gcc-4.9 20 | - g++-4.9 21 | - gdb 22 | # OSX, OF master 23 | - os: osx 24 | osx_image: xcode8 25 | compiler: clang 26 | env: TARGET="osx" OF_BRANCH="master" 27 | 28 | # Linux ARM6, OF master 29 | - os: linux 30 | sudo: required 31 | dist: trusty 32 | env: TARGET="linuxarmv6l" OF_BRANCH="master" 33 | # Exclude the default build that would otherwise be generated 34 | # see https://github.com/travis-ci/travis-ci/issues/1228 35 | exclude: 36 | - compiler: gcc 37 | 38 | install: 39 | - echo "--" 40 | - echo "ENV VARS" 41 | - printenv 42 | - echo "------------------------------" 43 | - pwd 44 | - echo "000000000000000000000000000000" 45 | - pwd 46 | - cd $HOME 47 | - git clone --depth=1 --branch=CI-ADDON-TESTS https://github.com/bakercp/openFrameworks 48 | - cd openFrameworks 49 | - echo "111111111111111111111111111111" 50 | - pwd 51 | - scripts/ci/addons/install.sh 52 | - echo "222222222222222222222222222222" 53 | - pwd 54 | 55 | script: 56 | - echo "SCRIPT XXXXXXXXXXXXXXXXXXXXXXXX" 57 | - $HOME/openFrameworks/scripts/ci/addons/build.sh 58 | - echo "333333333333333333333333333333" 59 | - pwd 60 | 61 | git: 62 | depth: 10 63 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Christopher Baker 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 | ofxJSONRPC 2 | ========== 3 | 4 | Description 5 | ----------- 6 | 7 | Create a JSONRPC server application with openFrameworks. This allows you to easily communicate between a browser and an openFrameworks application. 8 | 9 | Features 10 | -------- 11 | 12 | ![Screenshot](https://github.com/bakercp/ofxJSONRPC/raw/master/docs/screen.png) 13 | 14 | [JSONRPC 2.0](http://www.jsonrpc.org/specification) Implementation using openFrameworks events, WebSockets, etc. 15 | 16 | Easily communicate between the browser and an openFrameworks application with the well-documented JSONRPC 2.0 protocol. 17 | 18 | Compatible with [jquery.jsonrpcclient.js](https://github.com/Textalk/jquery.jsonrpcclient.js) on the client side. 19 | 20 | See examples and documentation for more information. 21 | 22 | Getting Started 23 | --------------- 24 | 25 | To get started, generate the example project files using the openFrameworks [Project Generator](http://openframeworks.cc/learning/01_basics/how_to_add_addon_to_project/). 26 | 27 | Documentation 28 | ------------- 29 | 30 | API documentation can be found here. 31 | 32 | Build Status 33 | ------------ 34 | 35 | Linux, macOS [![Build Status](https://travis-ci.org/bakercp/ofxJSONRPC.svg?branch=master)](https://travis-ci.org/bakercp/ofxJSONRPC) 36 | 37 | Visual Studio, MSYS [![Build status](https://ci.appveyor.com/api/projects/status/knek9qnt6ycl5ra9/branch/master?svg=true)](https://ci.appveyor.com/project/bakercp/ofxjsonrpc/branch/master) 38 | 39 | Compatibility 40 | ------------- 41 | 42 | ### Branches 43 | 44 | The `stable` branch of this repository is meant to be compatible with the openFrameworks [stable branch](https://github.com/openframeworks/openFrameworks/tree/stable), which corresponds to the latest official openFrameworks release. 45 | 46 | The `master` branch of this repository is meant to be compatible with the openFrameworks [master branch](https://github.com/openframeworks/openFrameworks/tree/master). 47 | 48 | Some past openFrameworks releases are supported via tagged versions, but only `stable` and `master` branches are actively supported. 49 | 50 | ### Requirements 51 | - [ofxHTTP](https://github.com/bakercp/ofxHTTP) 52 | - [ofxIO](https://github.com/bakercp/ofxIO) 53 | - [ofxMediaType](https://github.com/bakercp/ofxMediaType) 54 | - [ofxSSLManager](https://github.com/bakercp/ofxSSLManager) 55 | - [ofxNetworkUtils](https://github.com/bakercp/ofxNetworkUtils) 56 | - ofxPoco (included in openFrameworks core) 57 | 58 | Versioning 59 | ---------- 60 | 61 | This project uses [Semantic Versioning](http://semver.org/), although strict adherence will only come into effect at version 1.0.0. 62 | 63 | Licensing 64 | --------- 65 | 66 | See [LICENSE.md](LICENSE.md). 67 | 68 | Contributing 69 | ------------ 70 | 71 | Pull Requests are always welcome, so if you make any improvements please feel free to float them back upstream :) 72 | 73 | 1. Fork this repository. 74 | 2. Create your feature branch (`git checkout -b my-new-feature`). 75 | 3. Commit your changes (`git commit -am 'Add some feature'`). 76 | 4. Push to the branch (`git push origin my-new-feature`). 77 | 5. Create new Pull Request. 78 | -------------------------------------------------------------------------------- /addon_config.mk: -------------------------------------------------------------------------------- 1 | meta: 2 | ADDON_NAME = ofxJSONRPC 3 | ADDON_DESCRIPTION = A JSONRPC server for use with Websockets or Post Requests 4 | ADDON_AUTHOR = Christopher Baker 5 | ADDON_TAGS = "http" "json" "jsonrpc" 6 | ADDON_URL = http://github.com/bakercp/ofxJSONRPC 7 | common: 8 | ADDON_DEPENDENCIES = ofxHTTP ofxIO ofxPoco ofxMediaType ofxNetworkUtils ofxSSLManager 9 | -------------------------------------------------------------------------------- /docs/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/docs/screen.png -------------------------------------------------------------------------------- /example/addons.make: -------------------------------------------------------------------------------- 1 | ofxHTTP 2 | ofxIO 3 | ofxJSONRPC 4 | ofxMediaType 5 | ofxNetworkUtils 6 | ofxPoco 7 | ofxSSLManager 8 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 404 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 24 |
25 |

404 - File Not Found

26 |
27 |
28 |

29 | Sorry ... your file was not found. 30 |

31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 16 | } 17 | 18 | .btn-default:active, 19 | .btn-primary:active, 20 | .btn-success:active, 21 | .btn-info:active, 22 | .btn-warning:active, 23 | .btn-danger:active, 24 | .btn-default.active, 25 | .btn-primary.active, 26 | .btn-success.active, 27 | .btn-info.active, 28 | .btn-warning.active, 29 | .btn-danger.active { 30 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 31 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 32 | } 33 | 34 | .btn:active, 35 | .btn.active { 36 | background-image: none; 37 | } 38 | 39 | .btn-default { 40 | text-shadow: 0 1px 0 #fff; 41 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); 42 | background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); 43 | background-repeat: repeat-x; 44 | border-color: #dbdbdb; 45 | border-color: #ccc; 46 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 47 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 48 | } 49 | 50 | .btn-default:hover, 51 | .btn-default:focus { 52 | background-color: #e0e0e0; 53 | background-position: 0 -15px; 54 | } 55 | 56 | .btn-default:active, 57 | .btn-default.active { 58 | background-color: #e0e0e0; 59 | border-color: #dbdbdb; 60 | } 61 | 62 | .btn-primary { 63 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 64 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 65 | background-repeat: repeat-x; 66 | border-color: #2b669a; 67 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 68 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 69 | } 70 | 71 | .btn-primary:hover, 72 | .btn-primary:focus { 73 | background-color: #2d6ca2; 74 | background-position: 0 -15px; 75 | } 76 | 77 | .btn-primary:active, 78 | .btn-primary.active { 79 | background-color: #2d6ca2; 80 | border-color: #2b669a; 81 | } 82 | 83 | .btn-success { 84 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 85 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 86 | background-repeat: repeat-x; 87 | border-color: #3e8f3e; 88 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 89 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 90 | } 91 | 92 | .btn-success:hover, 93 | .btn-success:focus { 94 | background-color: #419641; 95 | background-position: 0 -15px; 96 | } 97 | 98 | .btn-success:active, 99 | .btn-success.active { 100 | background-color: #419641; 101 | border-color: #3e8f3e; 102 | } 103 | 104 | .btn-warning { 105 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 106 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 107 | background-repeat: repeat-x; 108 | border-color: #e38d13; 109 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 110 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 111 | } 112 | 113 | .btn-warning:hover, 114 | .btn-warning:focus { 115 | background-color: #eb9316; 116 | background-position: 0 -15px; 117 | } 118 | 119 | .btn-warning:active, 120 | .btn-warning.active { 121 | background-color: #eb9316; 122 | border-color: #e38d13; 123 | } 124 | 125 | .btn-danger { 126 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 127 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 128 | background-repeat: repeat-x; 129 | border-color: #b92c28; 130 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 131 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 132 | } 133 | 134 | .btn-danger:hover, 135 | .btn-danger:focus { 136 | background-color: #c12e2a; 137 | background-position: 0 -15px; 138 | } 139 | 140 | .btn-danger:active, 141 | .btn-danger.active { 142 | background-color: #c12e2a; 143 | border-color: #b92c28; 144 | } 145 | 146 | .btn-info { 147 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 148 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 149 | background-repeat: repeat-x; 150 | border-color: #28a4c9; 151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 153 | } 154 | 155 | .btn-info:hover, 156 | .btn-info:focus { 157 | background-color: #2aabd2; 158 | background-position: 0 -15px; 159 | } 160 | 161 | .btn-info:active, 162 | .btn-info.active { 163 | background-color: #2aabd2; 164 | border-color: #28a4c9; 165 | } 166 | 167 | .thumbnail, 168 | .img-thumbnail { 169 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 170 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 171 | } 172 | 173 | .dropdown-menu > li > a:hover, 174 | .dropdown-menu > li > a:focus { 175 | background-color: #e8e8e8; 176 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 177 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 178 | background-repeat: repeat-x; 179 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 180 | } 181 | 182 | .dropdown-menu > .active > a, 183 | .dropdown-menu > .active > a:hover, 184 | .dropdown-menu > .active > a:focus { 185 | background-color: #357ebd; 186 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 187 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 188 | background-repeat: repeat-x; 189 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 190 | } 191 | 192 | .navbar-default { 193 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 194 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); 195 | background-repeat: repeat-x; 196 | border-radius: 4px; 197 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 198 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 199 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 200 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 201 | } 202 | 203 | .navbar-default .navbar-nav > .active > a { 204 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 205 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 206 | background-repeat: repeat-x; 207 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 208 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 209 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 210 | } 211 | 212 | .navbar-brand, 213 | .navbar-nav > li > a { 214 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); 215 | } 216 | 217 | .navbar-inverse { 218 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); 219 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); 220 | background-repeat: repeat-x; 221 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 222 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 223 | } 224 | 225 | .navbar-inverse .navbar-nav > .active > a { 226 | background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); 227 | background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); 228 | background-repeat: repeat-x; 229 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 230 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 231 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 232 | } 233 | 234 | .navbar-inverse .navbar-brand, 235 | .navbar-inverse .navbar-nav > li > a { 236 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 237 | } 238 | 239 | .navbar-static-top, 240 | .navbar-fixed-top, 241 | .navbar-fixed-bottom { 242 | border-radius: 0; 243 | } 244 | 245 | .alert { 246 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); 247 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 248 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 249 | } 250 | 251 | .alert-success { 252 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 253 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 254 | background-repeat: repeat-x; 255 | border-color: #b2dba1; 256 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 257 | } 258 | 259 | .alert-info { 260 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 261 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 262 | background-repeat: repeat-x; 263 | border-color: #9acfea; 264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 265 | } 266 | 267 | .alert-warning { 268 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 269 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 270 | background-repeat: repeat-x; 271 | border-color: #f5e79e; 272 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 273 | } 274 | 275 | .alert-danger { 276 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 277 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 278 | background-repeat: repeat-x; 279 | border-color: #dca7a7; 280 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 281 | } 282 | 283 | .progress { 284 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 285 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 286 | background-repeat: repeat-x; 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 288 | } 289 | 290 | .progress-bar { 291 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 292 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 293 | background-repeat: repeat-x; 294 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 295 | } 296 | 297 | .progress-bar-success { 298 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 299 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 300 | background-repeat: repeat-x; 301 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 302 | } 303 | 304 | .progress-bar-info { 305 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 306 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 307 | background-repeat: repeat-x; 308 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 309 | } 310 | 311 | .progress-bar-warning { 312 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 313 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 314 | background-repeat: repeat-x; 315 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 316 | } 317 | 318 | .progress-bar-danger { 319 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 320 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 321 | background-repeat: repeat-x; 322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 323 | } 324 | 325 | .list-group { 326 | border-radius: 4px; 327 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 328 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 329 | } 330 | 331 | .list-group-item.active, 332 | .list-group-item.active:hover, 333 | .list-group-item.active:focus { 334 | text-shadow: 0 -1px 0 #3071a9; 335 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 336 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 337 | background-repeat: repeat-x; 338 | border-color: #3278b3; 339 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 340 | } 341 | 342 | .panel { 343 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 344 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 345 | } 346 | 347 | .panel-default > .panel-heading { 348 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 349 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 350 | background-repeat: repeat-x; 351 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 352 | } 353 | 354 | .panel-primary > .panel-heading { 355 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 356 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 357 | background-repeat: repeat-x; 358 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 359 | } 360 | 361 | .panel-success > .panel-heading { 362 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 363 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 364 | background-repeat: repeat-x; 365 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 366 | } 367 | 368 | .panel-info > .panel-heading { 369 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 370 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 371 | background-repeat: repeat-x; 372 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 373 | } 374 | 375 | .panel-warning > .panel-heading { 376 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 377 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 378 | background-repeat: repeat-x; 379 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 380 | } 381 | 382 | .panel-danger > .panel-heading { 383 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 384 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 385 | background-repeat: repeat-x; 386 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 387 | } 388 | 389 | .well { 390 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 391 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 392 | background-repeat: repeat-x; 393 | border-color: #dcdcdc; 394 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 395 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 396 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 397 | } -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * prism.js Twilight theme 3 | * Based (more or less) on the Twilight theme originally of Textmate fame. 4 | * @author Remy Bach 5 | */ 6 | code[class*="language-"], 7 | pre[class*="language-"] { 8 | color: white; 9 | direction: ltr; 10 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 11 | text-align: left; 12 | text-shadow: 0 -.1em .2em black; 13 | white-space: pre; 14 | word-spacing: normal; 15 | word-break: normal; 16 | 17 | -moz-tab-size: 4; 18 | -o-tab-size: 4; 19 | tab-size: 4; 20 | 21 | -webkit-hyphens: none; 22 | -moz-hyphens: none; 23 | -ms-hyphens: none; 24 | hyphens: none; 25 | } 26 | 27 | pre[class*="language-"], 28 | :not(pre) > code[class*="language-"] { 29 | background:hsl(0, 0%, 8%); /* #141414 */ 30 | } 31 | 32 | /* Code blocks */ 33 | pre[class*="language-"] { 34 | border-radius: .5em; 35 | border: .3em solid hsl(0,0%,33%); /* #282A2B */ 36 | box-shadow: 1px 1px .5em black inset; 37 | margin: .5em 0; 38 | overflow: auto; 39 | padding: 1em; 40 | } 41 | pre[class*="language-"]::selection { /* Safari */ 42 | background:hsl(200, 4%, 16%); /* #282A2B */ 43 | } 44 | pre[class*="language-"]::selection { /* Firefox */ 45 | background:hsl(200, 4%, 16%); /* #282A2B */ 46 | } 47 | 48 | /* Text Selection colour */ 49 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 50 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 51 | text-shadow: none; 52 | background: hsla(0,0%,93%,0.15); /* #EDEDED */ 53 | } 54 | 55 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 56 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 57 | text-shadow: none; 58 | background: hsla(0,0%,93%,0.15); /* #EDEDED */ 59 | } 60 | 61 | /* Inline code */ 62 | :not(pre) > code[class*="language-"] { 63 | border-radius: .3em; 64 | border: .13em solid hsl(0,0%,33%); /* #545454 */ 65 | box-shadow: 1px 1px .3em -.1em black inset; 66 | padding: .15em .2em .05em; 67 | } 68 | 69 | .token.comment, 70 | .token.prolog, 71 | .token.doctype, 72 | .token.cdata { 73 | color: hsl(0, 0%, 47%); /* #777777 */ 74 | } 75 | 76 | .token.punctuation { 77 | opacity: .7; 78 | } 79 | 80 | .namespace { 81 | opacity: .7; 82 | } 83 | 84 | .token.tag, 85 | .token.boolean, 86 | .token.number { 87 | color: hsl(14, 58%, 55%); /* #CF6A4C */ 88 | } 89 | 90 | .token.keyword, 91 | .token.property, 92 | .token.selector, 93 | .token.constant, 94 | .token.symbol, 95 | .token.builtin { 96 | color:hsl(53, 89%, 79%); /* #F9EE98 */ 97 | } 98 | .token.attr-name, 99 | .token.attr-value, 100 | .token.string, 101 | .token.operator, 102 | .token.entity, 103 | .token.url, 104 | .language-css .token.string, 105 | .style .token.string, 106 | .token.variable { 107 | color:hsl(76, 21%, 52%); /* #8F9D6A */ 108 | } 109 | 110 | .token.atrule { 111 | color:hsl(218, 22%, 55%); /* #7587A6 */ 112 | } 113 | 114 | .token.regex, 115 | .token.important { 116 | color: hsl(42, 75%, 65%); /* #E9C062 */ 117 | } 118 | 119 | .token.important { 120 | font-weight: bold; 121 | } 122 | 123 | .token.entity { 124 | cursor: help; 125 | } 126 | pre[data-line] { 127 | padding: 1em 0 1em 3em; 128 | position: relative; 129 | } 130 | 131 | /* Markup */ 132 | .language-markup .token.tag, 133 | .language-markup .token.attr-name, 134 | .language-markup .token.punctuation { 135 | color: hsl(33, 33%, 52%); /* #AC885B */ 136 | } 137 | 138 | /* Make the tokens sit above the line highlight so the colours don't look faded. */ 139 | .token { 140 | position:relative; 141 | z-index:1; 142 | } 143 | .line-highlight { 144 | background: -moz-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 145 | background: -o-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 146 | background: -webkit-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 147 | background: hsla(0, 0%, 33%, 0.25); /* #545454 */ 148 | background: linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 149 | border-bottom:1px dashed hsl(0, 0%, 33%); /* #545454 */ 150 | border-top:1px dashed hsl(0, 0%, 33%); /* #545454 */ 151 | left: 0; 152 | line-height: inherit; 153 | margin-top: 0.75em; /* Same as .prism’s padding-top */ 154 | padding: inherit 0; 155 | pointer-events: none; 156 | position: absolute; 157 | right: 0; 158 | white-space: pre; 159 | z-index:0; 160 | } 161 | .line-highlight:before, 162 | .line-highlight[data-end]:after { 163 | background-color: hsl(215, 15%, 59%); /* #8794A6 */ 164 | border-radius: 999px; 165 | box-shadow: 0 1px white; 166 | color: hsl(24, 20%, 95%); /* #F5F2F0 */ 167 | content: attr(data-start); 168 | font: bold 65%/1.5 sans-serif; 169 | left: .6em; 170 | min-width: 1em; 171 | padding: 0 .5em; 172 | position: absolute; 173 | text-align: center; 174 | text-shadow: none; 175 | top: .4em; 176 | vertical-align: .3em; 177 | } 178 | .line-highlight[data-end]:after { 179 | bottom: .4em; 180 | content: attr(data-end); 181 | top: auto; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/css/style.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin CSS Example 8.8.2 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * http://www.opensource.org/licenses/MIT 11 | */ 12 | 13 | body { 14 | padding-top: 60px; 15 | } 16 | 17 | /* 18 | * http://stackoverflow.com/questions/11223615/how-to-use-font-awesome-for-checkboxes-etc 19 | */ 20 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/img/favicon.ico -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/img/openFrameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/DocumentRoot/img/openFrameworks.png -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ofx::HTTP::BasicJSONRPCServer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 |
30 |

Basic JSONRPC Websocket Server Demo

31 |
32 |
33 |

34 | ofx::HTTP::BasicJSONRPCServer is a simple server for processing JSONRPC calls. 35 |

36 |
37 | 38 |
39 |
40 |
41 | Send Text to the Server (Look for your red and yellow text in the app window) 42 |
43 |
44 | 52 |
53 | 54 |
55 |
56 |
57 | Get Text from the Server 58 |
59 |
60 | 68 |
69 | 70 |
71 |
72 |
73 | Ping the Server 74 |
75 |
76 | 80 |
81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/js/jquery.json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery JSON plugin 2.4.0 3 | * 4 | * @author Brantley Harris, 2009-2011 5 | * @author Timo Tijhof, 2011-2012 6 | * @source This plugin is heavily influenced by MochiKit's serializeJSON, which is 7 | * copyrighted 2005 by Bob Ippolito. 8 | * @source Brantley Harris wrote this plugin. It is based somewhat on the JSON.org 9 | * website's http://www.json.org/json2.js, which proclaims: 10 | * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that 11 | * I uphold. 12 | * @license MIT License 13 | */ 14 | (function ($) { 15 | 'use strict'; 16 | 17 | var escape = /["\\\x00-\x1f\x7f-\x9f]/g, 18 | meta = { 19 | '\b': '\\b', 20 | '\t': '\\t', 21 | '\n': '\\n', 22 | '\f': '\\f', 23 | '\r': '\\r', 24 | '"' : '\\"', 25 | '\\': '\\\\' 26 | }, 27 | hasOwn = Object.prototype.hasOwnProperty; 28 | 29 | /** 30 | * jQuery.toJSON 31 | * Converts the given argument into a JSON representation. 32 | * 33 | * @param o {Mixed} The json-serializable *thing* to be converted 34 | * 35 | * If an object has a toJSON prototype, that will be used to get the representation. 36 | * Non-integer/string keys are skipped in the object, as are keys that point to a 37 | * function. 38 | * 39 | */ 40 | $.toJSON = typeof JSON === 'object' && JSON.stringify ? JSON.stringify : function (o) { 41 | if (o === null) { 42 | return 'null'; 43 | } 44 | 45 | var pairs, k, name, val, 46 | type = $.type(o); 47 | 48 | if (type === 'undefined') { 49 | return undefined; 50 | } 51 | 52 | // Also covers instantiated Number and Boolean objects, 53 | // which are typeof 'object' but thanks to $.type, we 54 | // catch them here. I don't know whether it is right 55 | // or wrong that instantiated primitives are not 56 | // exported to JSON as an {"object":..}. 57 | // We choose this path because that's what the browsers did. 58 | if (type === 'number' || type === 'boolean') { 59 | return String(o); 60 | } 61 | if (type === 'string') { 62 | return $.quoteString(o); 63 | } 64 | if (typeof o.toJSON === 'function') { 65 | return $.toJSON(o.toJSON()); 66 | } 67 | if (type === 'date') { 68 | var month = o.getUTCMonth() + 1, 69 | day = o.getUTCDate(), 70 | year = o.getUTCFullYear(), 71 | hours = o.getUTCHours(), 72 | minutes = o.getUTCMinutes(), 73 | seconds = o.getUTCSeconds(), 74 | milli = o.getUTCMilliseconds(); 75 | 76 | if (month < 10) { 77 | month = '0' + month; 78 | } 79 | if (day < 10) { 80 | day = '0' + day; 81 | } 82 | if (hours < 10) { 83 | hours = '0' + hours; 84 | } 85 | if (minutes < 10) { 86 | minutes = '0' + minutes; 87 | } 88 | if (seconds < 10) { 89 | seconds = '0' + seconds; 90 | } 91 | if (milli < 100) { 92 | milli = '0' + milli; 93 | } 94 | if (milli < 10) { 95 | milli = '0' + milli; 96 | } 97 | return '"' + year + '-' + month + '-' + day + 'T' + 98 | hours + ':' + minutes + ':' + seconds + 99 | '.' + milli + 'Z"'; 100 | } 101 | 102 | pairs = []; 103 | 104 | if ($.isArray(o)) { 105 | for (k = 0; k < o.length; k++) { 106 | pairs.push($.toJSON(o[k]) || 'null'); 107 | } 108 | return '[' + pairs.join(',') + ']'; 109 | } 110 | 111 | // Any other object (plain object, RegExp, ..) 112 | // Need to do typeof instead of $.type, because we also 113 | // want to catch non-plain objects. 114 | if (typeof o === 'object') { 115 | for (k in o) { 116 | // Only include own properties, 117 | // Filter out inherited prototypes 118 | if (hasOwn.call(o, k)) { 119 | // Keys must be numerical or string. Skip others 120 | type = typeof k; 121 | if (type === 'number') { 122 | name = '"' + k + '"'; 123 | } else if (type === 'string') { 124 | name = $.quoteString(k); 125 | } else { 126 | continue; 127 | } 128 | type = typeof o[k]; 129 | 130 | // Invalid values like these return undefined 131 | // from toJSON, however those object members 132 | // shouldn't be included in the JSON string at all. 133 | if (type !== 'function' && type !== 'undefined') { 134 | val = $.toJSON(o[k]); 135 | pairs.push(name + ':' + val); 136 | } 137 | } 138 | } 139 | return '{' + pairs.join(',') + '}'; 140 | } 141 | }; 142 | 143 | /** 144 | * jQuery.evalJSON 145 | * Evaluates a given json string. 146 | * 147 | * @param str {String} 148 | */ 149 | $.evalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) { 150 | /*jshint evil: true */ 151 | return eval('(' + str + ')'); 152 | }; 153 | 154 | /** 155 | * jQuery.secureEvalJSON 156 | * Evals JSON in a way that is *more* secure. 157 | * 158 | * @param str {String} 159 | */ 160 | $.secureEvalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) { 161 | var filtered = 162 | str 163 | .replace(/\\["\\\/bfnrtu]/g, '@') 164 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 165 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''); 166 | 167 | if (/^[\],:{}\s]*$/.test(filtered)) { 168 | /*jshint evil: true */ 169 | return eval('(' + str + ')'); 170 | } 171 | throw new SyntaxError('Error parsing JSON, source is not valid.'); 172 | }; 173 | 174 | /** 175 | * jQuery.quoteString 176 | * Returns a string-repr of a string, escaping quotes intelligently. 177 | * Mostly a support function for toJSON. 178 | * Examples: 179 | * >>> jQuery.quoteString('apple') 180 | * "apple" 181 | * 182 | * >>> jQuery.quoteString('"Where are we going?", she asked.') 183 | * "\"Where are we going?\", she asked." 184 | */ 185 | $.quoteString = function (str) { 186 | if (str.match(escape)) { 187 | return '"' + str.replace(escape, function (a) { 188 | var c = meta[a]; 189 | if (typeof c === 'string') { 190 | return c; 191 | } 192 | c = a.charCodeAt(); 193 | return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); 194 | }) + '"'; 195 | } 196 | return '"' + str + '"'; 197 | }; 198 | 199 | }(jQuery)); 200 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/js/main.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | var JSONRPCClient; ///< The core JSONRPC WebSocket client. 26 | 27 | function addError(error) { 28 | console.log(error); 29 | } 30 | 31 | function onWebSocketOpen(ws) { 32 | console.log("on open"); 33 | console.log(ws); 34 | } 35 | 36 | function onWebSocketMessage(evt) { 37 | console.log("on message:"); 38 | console.log(evt.data); 39 | } 40 | 41 | function onWebSocketClose() { 42 | console.log("on close"); 43 | } 44 | 45 | function onWebSocketError() { 46 | console.log("on error"); 47 | } 48 | 49 | function initializeButtons() { 50 | $('#get-text').on('click', function() { 51 | var $this = $(this); 52 | JSONRPCClient.call('get-text', 53 | null, 54 | function(result) { 55 | $('#text-to-recieve').val(result); 56 | }, 57 | function(error) { 58 | addError(error); 59 | }); 60 | }); 61 | 62 | 63 | $('#set-text').on('click', function() { 64 | var $this = $(this); 65 | JSONRPCClient.call('set-text', 66 | $('#text-to-send').val(), 67 | function(result) {}, 68 | function(error) { 69 | addError(error); 70 | }); 71 | }); 72 | 73 | 74 | $('#ping').on('click', function() { 75 | console.log("pinging"); 76 | var $this = $(this); 77 | JSONRPCClient.notify('ping'); 78 | }); 79 | 80 | 81 | $('#pong').on('click', function() { 82 | console.log("poinging"); 83 | var $this = $(this); 84 | JSONRPCClient.notify('pong'); 85 | }); 86 | } 87 | 88 | $(document).ready(function() { 89 | // Initialize our JSONRPCClient 90 | JSONRPCClient = new $.JsonRpcClient({ 91 | ajaxUrl: getDefaultPostURL(), 92 | socketUrl: getDefaultWebSocketURL(), // get a websocket for the localhost 93 | onmessage: onWebSocketMessage, 94 | onopen: onWebSocketOpen, 95 | onclose: onWebSocketClose, 96 | onerror: onWebSocketError 97 | }); 98 | 99 | initializeButtons(); 100 | 101 | }); -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/js/ofxHTTP.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | // ofxHTTP ///////////////////////////////////////////////////////////////////// 26 | 27 | // function ofPixelHandler() 28 | // { 29 | // var CMD_PIXELS = "SET_PIXELS"; 30 | 31 | // var OF_PIXELS_MONO = 0; 32 | // var OF_PIXELS_RGB = 1; 33 | // var OF_PIXELS_RGBA = 2; 34 | // var OF_PIXELS_BGRA = 3; 35 | // var OF_PIXELS_RGB565 = 4; 36 | 37 | // var PIXELS_DATA_TYPE_ARRAY_BUFFER = 0; 38 | // var PIXELS_DATA_TYPE_BLOB = 1; 39 | 40 | // var _bIsWaitingForPixels = false; 41 | // var _dataType = PIXELS_DATA_TYPE_ARRAY_BUFFER; 42 | // var _type = OF_PIXELS_RGBA; 43 | // var _width = 0; 44 | // var _height = 0; 45 | // var _destination = ""; 46 | 47 | // } 48 | 49 | // ofPixelHandler.prototype = function() 50 | // { 51 | // isWaitingForPixels: function() 52 | // { 53 | // return this._bIsWaitingForPixels; 54 | // }, 55 | // getPixelsDataType: function() 56 | // { 57 | // return this._pixelsDataType; 58 | // }, 59 | // getPixelsType: function() 60 | // { 61 | // return this._pixelsType; 62 | // }, 63 | // getWidth: function() 64 | // { 65 | // return this._width; 66 | // }, 67 | // getHeight: function() 68 | // { 69 | // return this._height; 70 | // } 71 | // getDestination: function() 72 | // { 73 | // return this._destination; 74 | // } 75 | // handleMessage: function(message) 76 | // { 77 | 78 | 79 | // return false; 80 | 81 | // return true; 82 | // } 83 | 84 | // } 85 | 86 | //------------------------------------------------------------------------------ 87 | function ofxHTTPBasicWebSocketClient(supportedProtocols) 88 | { 89 | var _self = this; 90 | 91 | var _ws = null; // WebSocket 92 | var _wsDataType = "binary"; 93 | var _customPath = ""; 94 | var _suppotedSubProtocols = supportedProtocols || []; 95 | var _keepAliveInterval = 15000; // milliseconds 96 | var _keepAliveTimeout = null; // set with setTimeout() 97 | var _retryConnectTimer = null; // set with setInterval() 98 | var _retryConnectInterval = 5000; // milliseconds 99 | var _bIsRetryingConnect = false; // are we in the process of retrying 100 | var _maxConnectRetries = 10; // we will allow this many retries 101 | var _numConnectRetries = 0; // how many times have we retried to connect 102 | 103 | var _commandCallbacks = new Object(); 104 | 105 | var _sequenceReceived = 0; 106 | var _sequenceTransmited = 0; 107 | 108 | var _JSONRPClient = new $.JsonRpcClient({ 109 | getSocket: function() { 110 | return _ws; 111 | }, 112 | onmessage: function(evt) { 113 | _onMessage(evt); 114 | } 115 | }); 116 | 117 | //-------------------------------------------------------------------------- 118 | 119 | 120 | //-------------------------------------------------------------------------- 121 | var _onUpdateMessage = function(message) 122 | { 123 | ofLogNotice("onMessageUpdate"); 124 | } 125 | 126 | //-------------------------------------------------------------------------- 127 | var _onUpdateStatus = function(status) 128 | { 129 | ofLogNotice("onStatusUpdate"); 130 | } 131 | 132 | //-------------------------------------------------------------------------- 133 | var _sendKeepAlive = function() 134 | { 135 | ofLogNotice("sendKeepAlive"); 136 | } 137 | 138 | //-------------------------------------------------------------------------- 139 | var _onOpen = function(evt) 140 | { 141 | ofLogNotice("onOpen"); 142 | } 143 | 144 | //-------------------------------------------------------------------------- 145 | var _onMessage = function(evt) 146 | { 147 | ofLogNotice("onMessage " + evt.data); 148 | } 149 | 150 | //-------------------------------------------------------------------------- 151 | var _onClose = function(evt) 152 | { 153 | ofLogNotice("onClose"); 154 | } 155 | 156 | //-------------------------------------------------------------------------- 157 | var _onError = function(evt) 158 | { 159 | ofLogNotice("onError"); 160 | } 161 | 162 | //-------------------------------------------------------------------------- 163 | // make sure that the appropriate websocket scheme is used 164 | // i.e. ws:// or wss:// for secure connections 165 | this.getWebSocketURL = function() 166 | { 167 | // TODO : ws_host = window.location.href.replace(/(http|https)(:\/\/.*?)\//, 'ws$2'); 168 | var scheme; 169 | var url = document.URL; 170 | if(url.substring(0, 5) == "https") 171 | { 172 | scheme = "wss://"; 173 | url = url.substr(8); 174 | } 175 | else 176 | { 177 | scheme = "ws://"; 178 | 179 | if (url.substring(0, 4) == "http") 180 | { 181 | url = url.substr(7); 182 | } 183 | } 184 | 185 | url = url.split('/'); 186 | 187 | return scheme + url[0]; 188 | } 189 | 190 | //-------------------------------------------------------------------------- 191 | this.getWebSocketDataType = function() 192 | { 193 | return _wsDataType; 194 | } 195 | 196 | //-------------------------------------------------------------------------- 197 | this.getWebSocket = function() 198 | { 199 | return _ws; 200 | } 201 | 202 | //-------------------------------------------------------------------------- 203 | this.isConnected = function() 204 | { 205 | return _ws != null; 206 | } 207 | 208 | //-------------------------------------------------------------------------- 209 | this.getCustomPath = function() 210 | { 211 | return _customPath; 212 | } 213 | 214 | //-------------------------------------------------------------------------- 215 | this.setCustomPath = function(customPath) 216 | { 217 | _customPath = customPath; 218 | } 219 | 220 | //-------------------------------------------------------------------------- 221 | this.getKeepAliveInterval = function() 222 | { 223 | return _keepAliveInterval; 224 | } 225 | 226 | //-------------------------------------------------------------------------- 227 | this.setKeepAliveInterval = function(keepAliveInterval) 228 | { 229 | _keepAliveInterval = keepAliveInterval; 230 | } 231 | 232 | //-------------------------------------------------------------------------- 233 | this.getSupportedSubProtocols = function() 234 | { 235 | return _suppotedSubProtocols; 236 | } 237 | 238 | //-------------------------------------------------------------------------- 239 | this.getRetryConnectInterval = function() 240 | { 241 | return _retryConnectInterval; 242 | } 243 | 244 | //-------------------------------------------------------------------------- 245 | this.setRetryConnectInterval = function(retryConnectInterval) 246 | { 247 | _retryConnectInterval = retryConnectInterval; 248 | } 249 | 250 | //-------------------------------------------------------------------------- 251 | this.isRetryingConnect = function() 252 | { 253 | return _isRetryingConnect; 254 | } 255 | 256 | //-------------------------------------------------------------------------- 257 | this.getMaxConnectRetries = function() 258 | { 259 | return _maxConnectRetries; 260 | } 261 | 262 | //-------------------------------------------------------------------------- 263 | this.setMaxConnectRetries = function(maxConnectRetries) 264 | { 265 | _maxConnectRetries = maxConnectRetries; 266 | } 267 | 268 | //-------------------------------------------------------------------------- 269 | this.setBinaryType = function(binaryType) 270 | { 271 | if(_self.isConnected()) 272 | { 273 | if(binaryType == "blob" || 274 | binaryType == "arraybuffer") 275 | { 276 | _ws.binaryType = binaryType; 277 | } 278 | else 279 | { 280 | ofLogError("Unknown binaryType: " + binaryType); 281 | } 282 | } 283 | else 284 | { 285 | ofLogError("WebSocket has not been initialized. Please call connect() first."); 286 | } 287 | } 288 | 289 | //-------------------------------------------------------------------------- 290 | this.setOnOpen = function(fn) 291 | { 292 | _onOpen = fn; 293 | } 294 | 295 | //-------------------------------------------------------------------------- 296 | this.setOnMessage = function(fn) 297 | { 298 | _onMessage = fn; 299 | } 300 | 301 | //-------------------------------------------------------------------------- 302 | this.setOnClose = function(fn) 303 | { 304 | _onClose = fn; 305 | } 306 | 307 | //-------------------------------------------------------------------------- 308 | this.setOnError = function(fn) 309 | { 310 | _onError = fn; 311 | } 312 | 313 | //-------------------------------------------------------------------------- 314 | this.getBufferedAmount = function() 315 | { 316 | if(_self.isConnected()) 317 | { 318 | return _ws.bufferedAmount; 319 | } 320 | else 321 | { 322 | ofLogError("WebSocket has not been initialized. Please call connect() first."); 323 | return -1; 324 | } 325 | } 326 | 327 | //-------------------------------------------------------------------------- 328 | this.connect = function() 329 | { 330 | if("WebSocket" in window) 331 | { 332 | try 333 | { 334 | _ws = new WebSocket(_self.getWebSocketURL(), 335 | _self.getSupportedSubProtocols()); 336 | 337 | _ws.onopen = function(evt) 338 | { 339 | _onOpen(evt); // our event 340 | 341 | _retryConnectTimer = setInterval( 342 | function() 343 | { 344 | _sendKeepAlive(); 345 | }, 346 | _self.getKeepAliveInterval() 347 | ); 348 | } 349 | 350 | _ws.onmessage = function(evt) 351 | { 352 | _onMessage(evt); 353 | } 354 | 355 | _ws.onclose = function(evt) 356 | { 357 | clearInterval(_retryConnectTimer); 358 | 359 | if(!evt.wasClean || evt.code == 1006 /* 1006 == abnormal closure */) 360 | { 361 | if(_self.getSupportedSubProtocols().length > 0 && 362 | _self.getSupportedSubProtocols().hasObject(evt.target.protocol)) 363 | { 364 | ofLogError("None of the proposed subprotocols [" + _self.getSupportedSubProtocols() + "] were supported by the server."); 365 | } 366 | else 367 | { 368 | ofLogError("Closed for an unknown reason, code: " + evt.code); 369 | } 370 | } 371 | 372 | _onClose(evt); // our event 373 | } 374 | 375 | _ws.onerror = function(evt) 376 | { 377 | _onError(evt); 378 | } 379 | 380 | } catch(exception) { 381 | ofLogError(exception); 382 | } 383 | } 384 | else 385 | { 386 | alert("This browser does not support WebSockets. Please upgrade your browser."); 387 | } 388 | } 389 | 390 | //-------------------------------------------------------------------------- 391 | this.disconnect = function() 392 | { 393 | if(_self.isConnected()) 394 | { 395 | window.clearInterval(_keepAliveTimeout); 396 | _ws.close(); 397 | _ws = null; 398 | } 399 | else 400 | { 401 | ofLogError("WebSocket has not been initialized. Please call connect first."); 402 | } 403 | } 404 | 405 | //-------------------------------------------------------------------------- 406 | this.send = function(val) 407 | { 408 | // this will be reset each time 409 | window.clearInterval(_keepAliveTimeout); 410 | _keepAliveTimeout = window.setInterval(_sendKeepAlive, 411 | _keepAliveInterval); 412 | 413 | // lastSendTime = now 414 | _ws.send(val); 415 | 416 | ofLogVerbose("Sent " + val); 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /example/bin/data/DocumentRoot/js/ofxUtils.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | // HELPER ////////////////////////////////////////////////////////////////////// 26 | Array.prototype.hasObject = ( 27 | !Array.indexOf ? function (o) { 28 | var l = this.length + 1; 29 | while (l -= 1) { 30 | if (this[l - 1] === o) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } : function (o) { 36 | return (this.indexOf(o) !== -1); 37 | } 38 | ); 39 | 40 | // LOGGING ///////////////////////////////////////////////////////////////////// 41 | var OF_LOG_VERBOSE = 0; 42 | var OF_LOG_NOTICE = 1; 43 | var OF_LOG_WARNING = 2; 44 | var OF_LOG_ERROR = 3; 45 | var OF_LOG_FATAL_ERROR = 4; 46 | var OF_LOG_SILENT = 5; 47 | 48 | var logLevel = OF_LOG_VERBOSE; 49 | 50 | function ofGetLogLevelName(_logLevel) 51 | { 52 | switch(_logLevel) 53 | { 54 | case OF_LOG_VERBOSE: 55 | return "OF_LOG_VERBOSE"; 56 | case OF_LOG_NOTICE: 57 | return "OF_LOG_NOTICE"; 58 | case OF_LOG_WARNING: 59 | return "OF_LOG_WARNING"; 60 | case OF_LOG_ERROR: 61 | return "OF_LOG_ERROR"; 62 | case OF_LOG_FATAL_ERROR: 63 | return "OF_LOG_FATAL_ERROR"; 64 | case OF_LOG_SILENT: 65 | return "OF_LOG_SILENT"; 66 | default: 67 | return "UNKNOWN_LOG_LEVEL"; 68 | } 69 | } 70 | 71 | function ofGetLogLevel() 72 | { 73 | return logLevel; 74 | } 75 | 76 | function ofSetLogLevel(_logLevel) 77 | { 78 | logLevel = _logLevel; 79 | } 80 | 81 | function ofLog(logLevel,val) 82 | { 83 | if(logLevel >= ofGetLogLevel()) 84 | { 85 | console.log(val); 86 | } 87 | } 88 | 89 | function ofLogVerbose(_message) 90 | { 91 | ofLog(self.OF_LOG_VERBOSE, _message); 92 | } 93 | 94 | function ofLogNotice(_message) 95 | { 96 | ofLog(self.OF_LOG_NOTICE, _message); 97 | } 98 | 99 | function ofLogWarning(_message) 100 | { 101 | ofLog(self.OF_LOG_WARNING, _message); 102 | } 103 | 104 | function ofLogError(_message) 105 | { 106 | ofLog(self.OF_LOG_ERROR, _message); 107 | } 108 | 109 | function ofLogFatalError(_message) 110 | { 111 | ofLog(self.OF_LOG_FATAL_ERROR, _message); 112 | } 113 | 114 | function ofLogSilent(_message) 115 | { 116 | ofLog(self.OF_LOG_SILENT, _message); 117 | } 118 | 119 | // UTILITIES /////////////////////////////////////////////////////////////////// 120 | 121 | function ofClamp(val,max,min) 122 | { 123 | return (val < min ? max : (val > min ? min : val)); 124 | } 125 | 126 | 127 | //-------------------------------------------------------------------------- 128 | // make sure that the appropriate websocket scheme is used 129 | // i.e. ws:// or wss:// for secure connections 130 | function getDefaultWebSocketURL() 131 | { 132 | var scheme; 133 | var url = document.URL; 134 | if(url.substring(0, 5) == "https") 135 | { 136 | scheme = "wss://"; 137 | url = url.substr(8); 138 | } 139 | else 140 | { 141 | scheme = "ws://"; 142 | 143 | if (url.substring(0, 4) == "http") 144 | { 145 | url = url.substr(7); 146 | } 147 | } 148 | 149 | url = url.split('/'); 150 | 151 | return scheme + url[0]; 152 | } 153 | 154 | //-------------------------------------------------------------------------- 155 | function getDefaultPostURL() 156 | { 157 | return document.URL + "post"; 158 | } 159 | -------------------------------------------------------------------------------- /example/bin/data/media/ipsum.txt: -------------------------------------------------------------------------------- 1 | Ethnic viral hoodie literally Pinterest, Marfa sriracha. Shabby chic food truck chia yr skateboard single-origin coffee kogi, bicycle rights Shoreditch next level flannel. Try-hard DIY gastropub small batch, ethical post-ironic Schlitz ennui cornhole aesthetic. Organic swag master cleanse +1 cred, disrupt irony American Apparel photo booth freegan normcore 3 wolf moon Truffaut food truck viral. Slow-carb ethnic roof party craft beer. Ethical blog pug semiotics irony readymade, banh mi authentic selfies. Before they sold out letterpress Etsy four loko keffiyeh, sustainable drinking vinegar farm-to-table small batch McSweeney's ethnic direct trade fap. 2 | 3 | Try-hard Neutra quinoa mixtape fanny pack, Austin small batch chambray meh Etsy occupy retro. Cornhole Truffaut fingerstache, tofu deep v shabby chic crucifix YOLO Schlitz. Truffaut tote bag mixtape photo booth master cleanse. Artisan PBR&B crucifix VHS. Mumblecore semiotics small batch Carles Thundercats butcher. Meh wayfarers food truck, master cleanse +1 banh mi scenester distillery Odd Future cred XOXO asymmetrical Blue Bottle. Trust fund wolf fanny pack, twee banjo XOXO McSweeney's typewriter Cosby sweater flexitarian. 4 | 5 | Wolf chambray four loko, single-origin coffee master cleanse whatever Odd Future. Literally farm-to-table aesthetic Wes Anderson VHS fanny pack fixie, food truck Echo Park Tonx Pitchfork normcore four loko lomo mumblecore. XOXO Pinterest cardigan raw denim sartorial, cliche Odd Future. Chillwave plaid fap cliche try-hard, locavore flexitarian Wes Anderson slow-carb. Stumptown Truffaut next level, butcher biodiesel pork belly Bushwick selfies twee Pinterest fap. Irony cornhole freegan small batch ethnic. DIY Schlitz fixie mustache actually Intelligentsia. 6 | 7 | Banksy Williamsburg sriracha salvia selfies, biodiesel plaid Godard single-origin coffee ethical XOXO banh mi seitan Portland 90's. Hella gentrify photo booth wolf readymade fingerstache, post-ironic church-key Bushwick cliche food truck actually bespoke literally Shoreditch. Occupy butcher cornhole, organic Brooklyn YOLO crucifix trust fund hella sustainable blog ethical typewriter Marfa American Apparel. Yr cray street art Kickstarter you probably haven't heard of them. Ethnic ugh sartorial chillwave Thundercats, tote bag Carles sustainable gentrify VHS distillery slow-carb Bushwick Odd Future. Quinoa kogi XOXO you probably haven't heard of them, lo-fi master cleanse mlkshk raw denim chillwave chia try-hard sartorial fixie leggings ethnic. Semiotics readymade cred church-key iPhone wolf Tonx organic Cosby sweater, stumptown Banksy pickled selvage drinking vinegar direct trade. -------------------------------------------------------------------------------- /example/bin/data/media/ping.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/media/ping.wav -------------------------------------------------------------------------------- /example/bin/data/media/pong.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example/bin/data/media/pong.wav -------------------------------------------------------------------------------- /example/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofApp.h" 9 | 10 | 11 | int main() 12 | { 13 | ofSetupOpenGL(320, 240, OF_WINDOW); 14 | return ofRunApp(std::make_shared()); 15 | } 16 | -------------------------------------------------------------------------------- /example/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofApp.h" 9 | 10 | 11 | void ofApp::setup() 12 | { 13 | ofSetFrameRate(30); 14 | 15 | ofSetLogLevel(OF_LOG_VERBOSE); 16 | 17 | // Load test text. 18 | ipsum = ofBufferFromFile("media/ipsum.txt").getText(); 19 | 20 | // Load test media. 21 | pingPlayer.load("media/ping.wav"); 22 | pongPlayer.load("media/pong.wav"); 23 | 24 | ofx::HTTP::JSONRPCServerSettings settings; 25 | settings.setPort(8197); 26 | 27 | // Initialize the server. 28 | server.setup(settings); 29 | 30 | 31 | // Register RPC methods. 32 | server.registerMethod("get-text", 33 | "Returns a random chunk of text to the client.", 34 | this, 35 | &ofApp::getText); 36 | 37 | server.registerMethod("set-text", 38 | "Sets text from the user.", 39 | this, 40 | &ofApp::setText); 41 | 42 | server.registerMethod("ping", 43 | "Send a JSONRPC Ping Notification", 44 | this, 45 | &ofApp::ping); 46 | 47 | server.registerMethod("pong", 48 | "Send a JSONRPC Pong Notification", 49 | this, 50 | &ofApp::pong); 51 | 52 | // Start the server. 53 | server.start(); 54 | 55 | // Launch a browser with the address of the server. 56 | ofLaunchBrowser(server.url()); 57 | } 58 | 59 | 60 | void ofApp::draw() 61 | { 62 | ofBackground(255); 63 | ofDrawBitmapStringHighlight("Open the URL: " + server.url(), 14, 18); 64 | ofDrawBitmapStringHighlight(userText, 14, 42, ofColor::yellow, ofColor::red); 65 | 66 | fader = ofClamp(fader - 10, 0, 255); 67 | ofDrawBitmapStringHighlight(fadingText, 68 | ofGetWidth() / 2 - 25, 69 | ofGetHeight() / 2, 70 | ofColor(0, fader), 71 | ofColor(255, fader)); 72 | } 73 | 74 | 75 | void ofApp::exit() 76 | { 77 | // Set the logger back to the default to make sure any 78 | // remaining messages are logged correctly. 79 | ofLogToConsole(); 80 | } 81 | 82 | 83 | void ofApp::ping() 84 | { 85 | pingPlayer.play(); 86 | ofLogVerbose("ofApp::ping") << "Ping'd"; 87 | fadingText = "ping!"; 88 | fader = 255; 89 | } 90 | 91 | 92 | void ofApp::pong() 93 | { 94 | pongPlayer.play(); 95 | ofLogVerbose("ofApp::pong") << "Pong'd"; 96 | fadingText = "pong!"; 97 | fader = 255; 98 | } 99 | 100 | 101 | void ofApp::getText(ofx::JSONRPC::MethodArgs& args) 102 | { 103 | // Set the result equal to the substring. 104 | args.result = getRandomText(); 105 | ofLogVerbose("ofApp::getText") << args.result.dump(4); 106 | } 107 | 108 | 109 | void ofApp::setText(ofx::JSONRPC::MethodArgs& args) 110 | { 111 | // Set the user text. 112 | setUserText(args.params); 113 | ofLogVerbose("ofApp::setText") << args.params.dump(4); 114 | } 115 | 116 | 117 | std::string ofApp::getRandomText() const 118 | { 119 | static const std::size_t LENGTH = 140; 120 | 121 | std::unique_lock lock(mutex); 122 | 123 | // Generate a random start index. 124 | std::size_t startIndex = (std::size_t)ofRandom(ipsum.length()); 125 | 126 | // Ensure that the length is valid. 127 | std::size_t length = (startIndex + LENGTH) < ipsum.length() ? LENGTH : string::npos; 128 | 129 | // return the result equal to the substring. 130 | return ipsum.substr(startIndex, length); 131 | } 132 | 133 | 134 | std::string ofApp::getUserText() const 135 | { 136 | std::unique_lock lock(mutex); 137 | return userText; 138 | } 139 | 140 | 141 | void ofApp::setUserText(const std::string& text) 142 | { 143 | std::unique_lock lock(mutex); 144 | userText = text; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /example/src/ofApp.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include "ofMain.h" 12 | #include "ofxJSONRPC.h" 13 | 14 | 15 | class ofApp: public ofBaseApp 16 | { 17 | public: 18 | void setup() override; 19 | void draw() override; 20 | void exit() override; 21 | 22 | // Registered methods. 23 | void getText(ofx::JSONRPC::MethodArgs& args); 24 | void setText(ofx::JSONRPC::MethodArgs& args); 25 | 26 | // Register a no-argument notification method. 27 | void ping(); 28 | 29 | // Register a no-argument notification method. 30 | void pong(); 31 | 32 | /// \todo is ofSoundPlayer thread-safe? 33 | ofSoundPlayer pingPlayer; 34 | ofSoundPlayer pongPlayer; 35 | 36 | /// \brief The server that handles the JSONRPC requests. 37 | ofx::HTTP::JSONRPCServer server; 38 | 39 | /// \brief Get a snippet of random text in a thread-safe way. 40 | /// \returns The snippet of random text. 41 | std::string getRandomText() const; 42 | 43 | /// \brief Get the user text in a thread-safe way. 44 | /// \returns The user text. 45 | std::string getUserText() const; 46 | 47 | /// \brief Set the user text in a thread-safe way. 48 | /// \param text the user text to set. 49 | void setUserText(const std::string& text); 50 | 51 | private: 52 | // A custom logging channel to mirror all log messages to the web clients. 53 | // WebSocketLoggerChannel::SharedPtr loggerChannel; 54 | 55 | // This piece of text might be modified by multiple client threads. 56 | // Thus we must use a mutex to protect it during multi-threaded access. 57 | std::string ipsum; 58 | 59 | // This piece of text might be modified by multiple client threads. 60 | // Thus we must use a mutex to protect it during multi-threaded access. 61 | std::string userText; 62 | 63 | // We use a mutex to protect any variables that can be 64 | // modified by multiple clients. In our case, userText must be protected. 65 | // We mark the mutex as mutable so that it can be used in const functions. 66 | mutable std::mutex mutex; 67 | 68 | float fader = 0; 69 | std::string fadingText; 70 | 71 | }; 72 | -------------------------------------------------------------------------------- /example_no_window/addons.make: -------------------------------------------------------------------------------- 1 | ofxHTTP 2 | ofxIO 3 | ofxJSONRPC 4 | ofxMediaType 5 | ofxNetworkUtils 6 | ofxPoco 7 | ofxSSLManager 8 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 404 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 24 |
25 |

404 - File Not Found

26 |
27 |
28 |

29 | Sorry ... your file was not found. 30 |

31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * prism.js Twilight theme 3 | * Based (more or less) on the Twilight theme originally of Textmate fame. 4 | * @author Remy Bach 5 | */ 6 | code[class*="language-"], 7 | pre[class*="language-"] { 8 | color: white; 9 | direction: ltr; 10 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 11 | text-align: left; 12 | text-shadow: 0 -.1em .2em black; 13 | white-space: pre; 14 | word-spacing: normal; 15 | word-break: normal; 16 | 17 | -moz-tab-size: 4; 18 | -o-tab-size: 4; 19 | tab-size: 4; 20 | 21 | -webkit-hyphens: none; 22 | -moz-hyphens: none; 23 | -ms-hyphens: none; 24 | hyphens: none; 25 | } 26 | 27 | pre[class*="language-"], 28 | :not(pre) > code[class*="language-"] { 29 | background:hsl(0, 0%, 8%); /* #141414 */ 30 | } 31 | 32 | /* Code blocks */ 33 | pre[class*="language-"] { 34 | border-radius: .5em; 35 | border: .3em solid hsl(0,0%,33%); /* #282A2B */ 36 | box-shadow: 1px 1px .5em black inset; 37 | margin: .5em 0; 38 | overflow: auto; 39 | padding: 1em; 40 | } 41 | pre[class*="language-"]::selection { /* Safari */ 42 | background:hsl(200, 4%, 16%); /* #282A2B */ 43 | } 44 | pre[class*="language-"]::selection { /* Firefox */ 45 | background:hsl(200, 4%, 16%); /* #282A2B */ 46 | } 47 | 48 | /* Text Selection colour */ 49 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 50 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 51 | text-shadow: none; 52 | background: hsla(0,0%,93%,0.15); /* #EDEDED */ 53 | } 54 | 55 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 56 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 57 | text-shadow: none; 58 | background: hsla(0,0%,93%,0.15); /* #EDEDED */ 59 | } 60 | 61 | /* Inline code */ 62 | :not(pre) > code[class*="language-"] { 63 | border-radius: .3em; 64 | border: .13em solid hsl(0,0%,33%); /* #545454 */ 65 | box-shadow: 1px 1px .3em -.1em black inset; 66 | padding: .15em .2em .05em; 67 | } 68 | 69 | .token.comment, 70 | .token.prolog, 71 | .token.doctype, 72 | .token.cdata { 73 | color: hsl(0, 0%, 47%); /* #777777 */ 74 | } 75 | 76 | .token.punctuation { 77 | opacity: .7; 78 | } 79 | 80 | .namespace { 81 | opacity: .7; 82 | } 83 | 84 | .token.tag, 85 | .token.boolean, 86 | .token.number { 87 | color: hsl(14, 58%, 55%); /* #CF6A4C */ 88 | } 89 | 90 | .token.keyword, 91 | .token.property, 92 | .token.selector, 93 | .token.constant, 94 | .token.symbol, 95 | .token.builtin { 96 | color:hsl(53, 89%, 79%); /* #F9EE98 */ 97 | } 98 | .token.attr-name, 99 | .token.attr-value, 100 | .token.string, 101 | .token.operator, 102 | .token.entity, 103 | .token.url, 104 | .language-css .token.string, 105 | .style .token.string, 106 | .token.variable { 107 | color:hsl(76, 21%, 52%); /* #8F9D6A */ 108 | } 109 | 110 | .token.atrule { 111 | color:hsl(218, 22%, 55%); /* #7587A6 */ 112 | } 113 | 114 | .token.regex, 115 | .token.important { 116 | color: hsl(42, 75%, 65%); /* #E9C062 */ 117 | } 118 | 119 | .token.important { 120 | font-weight: bold; 121 | } 122 | 123 | .token.entity { 124 | cursor: help; 125 | } 126 | pre[data-line] { 127 | padding: 1em 0 1em 3em; 128 | position: relative; 129 | } 130 | 131 | /* Markup */ 132 | .language-markup .token.tag, 133 | .language-markup .token.attr-name, 134 | .language-markup .token.punctuation { 135 | color: hsl(33, 33%, 52%); /* #AC885B */ 136 | } 137 | 138 | /* Make the tokens sit above the line highlight so the colours don't look faded. */ 139 | .token { 140 | position:relative; 141 | z-index:1; 142 | } 143 | .line-highlight { 144 | background: -moz-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 145 | background: -o-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 146 | background: -webkit-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 147 | background: hsla(0, 0%, 33%, 0.25); /* #545454 */ 148 | background: linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */ 149 | border-bottom:1px dashed hsl(0, 0%, 33%); /* #545454 */ 150 | border-top:1px dashed hsl(0, 0%, 33%); /* #545454 */ 151 | left: 0; 152 | line-height: inherit; 153 | margin-top: 0.75em; /* Same as .prism’s padding-top */ 154 | padding: inherit 0; 155 | pointer-events: none; 156 | position: absolute; 157 | right: 0; 158 | white-space: pre; 159 | z-index:0; 160 | } 161 | .line-highlight:before, 162 | .line-highlight[data-end]:after { 163 | background-color: hsl(215, 15%, 59%); /* #8794A6 */ 164 | border-radius: 999px; 165 | box-shadow: 0 1px white; 166 | color: hsl(24, 20%, 95%); /* #F5F2F0 */ 167 | content: attr(data-start); 168 | font: bold 65%/1.5 sans-serif; 169 | left: .6em; 170 | min-width: 1em; 171 | padding: 0 .5em; 172 | position: absolute; 173 | text-align: center; 174 | text-shadow: none; 175 | top: .4em; 176 | vertical-align: .3em; 177 | } 178 | .line-highlight[data-end]:after { 179 | bottom: .4em; 180 | content: attr(data-end); 181 | top: auto; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/css/style.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin CSS Example 8.8.2 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * http://www.opensource.org/licenses/MIT 11 | */ 12 | 13 | body { 14 | padding-top: 60px; 15 | } 16 | 17 | /* 18 | * http://stackoverflow.com/questions/11223615/how-to-use-font-awesome-for-checkboxes-etc 19 | */ 20 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/img/favicon.ico -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/img/openFrameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/example_no_window/bin/data/DocumentRoot/img/openFrameworks.png -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ofx::HTTP::BasicJSONRPCServer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 |
30 |

Basic JSONRPC Websocket Server Demo

31 |
32 |
33 |

34 | ofx::HTTP::BasicJSONRPCServer is a simple server for processing JSONRPC calls. 35 |

36 |
37 | 38 |
39 |
40 |
41 | Send Text to the Server (Look for your red and yellow text in the app window) 42 |
43 |
44 | 52 |
53 | 54 |
55 |
56 |
57 | Get Text from the Server 58 |
59 |
60 | 68 |
69 | 70 |
71 |
72 |
73 | Ping the Server 74 |
75 |
76 | 80 |
81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/js/jquery.json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery JSON plugin 2.4.0 3 | * 4 | * @author Brantley Harris, 2009-2011 5 | * @author Timo Tijhof, 2011-2012 6 | * @source This plugin is heavily influenced by MochiKit's serializeJSON, which is 7 | * copyrighted 2005 by Bob Ippolito. 8 | * @source Brantley Harris wrote this plugin. It is based somewhat on the JSON.org 9 | * website's http://www.json.org/json2.js, which proclaims: 10 | * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that 11 | * I uphold. 12 | * @license MIT License 13 | */ 14 | (function ($) { 15 | 'use strict'; 16 | 17 | var escape = /["\\\x00-\x1f\x7f-\x9f]/g, 18 | meta = { 19 | '\b': '\\b', 20 | '\t': '\\t', 21 | '\n': '\\n', 22 | '\f': '\\f', 23 | '\r': '\\r', 24 | '"' : '\\"', 25 | '\\': '\\\\' 26 | }, 27 | hasOwn = Object.prototype.hasOwnProperty; 28 | 29 | /** 30 | * jQuery.toJSON 31 | * Converts the given argument into a JSON representation. 32 | * 33 | * @param o {Mixed} The json-serializable *thing* to be converted 34 | * 35 | * If an object has a toJSON prototype, that will be used to get the representation. 36 | * Non-integer/string keys are skipped in the object, as are keys that point to a 37 | * function. 38 | * 39 | */ 40 | $.toJSON = typeof JSON === 'object' && JSON.stringify ? JSON.stringify : function (o) { 41 | if (o === null) { 42 | return 'null'; 43 | } 44 | 45 | var pairs, k, name, val, 46 | type = $.type(o); 47 | 48 | if (type === 'undefined') { 49 | return undefined; 50 | } 51 | 52 | // Also covers instantiated Number and Boolean objects, 53 | // which are typeof 'object' but thanks to $.type, we 54 | // catch them here. I don't know whether it is right 55 | // or wrong that instantiated primitives are not 56 | // exported to JSON as an {"object":..}. 57 | // We choose this path because that's what the browsers did. 58 | if (type === 'number' || type === 'boolean') { 59 | return String(o); 60 | } 61 | if (type === 'string') { 62 | return $.quoteString(o); 63 | } 64 | if (typeof o.toJSON === 'function') { 65 | return $.toJSON(o.toJSON()); 66 | } 67 | if (type === 'date') { 68 | var month = o.getUTCMonth() + 1, 69 | day = o.getUTCDate(), 70 | year = o.getUTCFullYear(), 71 | hours = o.getUTCHours(), 72 | minutes = o.getUTCMinutes(), 73 | seconds = o.getUTCSeconds(), 74 | milli = o.getUTCMilliseconds(); 75 | 76 | if (month < 10) { 77 | month = '0' + month; 78 | } 79 | if (day < 10) { 80 | day = '0' + day; 81 | } 82 | if (hours < 10) { 83 | hours = '0' + hours; 84 | } 85 | if (minutes < 10) { 86 | minutes = '0' + minutes; 87 | } 88 | if (seconds < 10) { 89 | seconds = '0' + seconds; 90 | } 91 | if (milli < 100) { 92 | milli = '0' + milli; 93 | } 94 | if (milli < 10) { 95 | milli = '0' + milli; 96 | } 97 | return '"' + year + '-' + month + '-' + day + 'T' + 98 | hours + ':' + minutes + ':' + seconds + 99 | '.' + milli + 'Z"'; 100 | } 101 | 102 | pairs = []; 103 | 104 | if ($.isArray(o)) { 105 | for (k = 0; k < o.length; k++) { 106 | pairs.push($.toJSON(o[k]) || 'null'); 107 | } 108 | return '[' + pairs.join(',') + ']'; 109 | } 110 | 111 | // Any other object (plain object, RegExp, ..) 112 | // Need to do typeof instead of $.type, because we also 113 | // want to catch non-plain objects. 114 | if (typeof o === 'object') { 115 | for (k in o) { 116 | // Only include own properties, 117 | // Filter out inherited prototypes 118 | if (hasOwn.call(o, k)) { 119 | // Keys must be numerical or string. Skip others 120 | type = typeof k; 121 | if (type === 'number') { 122 | name = '"' + k + '"'; 123 | } else if (type === 'string') { 124 | name = $.quoteString(k); 125 | } else { 126 | continue; 127 | } 128 | type = typeof o[k]; 129 | 130 | // Invalid values like these return undefined 131 | // from toJSON, however those object members 132 | // shouldn't be included in the JSON string at all. 133 | if (type !== 'function' && type !== 'undefined') { 134 | val = $.toJSON(o[k]); 135 | pairs.push(name + ':' + val); 136 | } 137 | } 138 | } 139 | return '{' + pairs.join(',') + '}'; 140 | } 141 | }; 142 | 143 | /** 144 | * jQuery.evalJSON 145 | * Evaluates a given json string. 146 | * 147 | * @param str {String} 148 | */ 149 | $.evalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) { 150 | /*jshint evil: true */ 151 | return eval('(' + str + ')'); 152 | }; 153 | 154 | /** 155 | * jQuery.secureEvalJSON 156 | * Evals JSON in a way that is *more* secure. 157 | * 158 | * @param str {String} 159 | */ 160 | $.secureEvalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) { 161 | var filtered = 162 | str 163 | .replace(/\\["\\\/bfnrtu]/g, '@') 164 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 165 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''); 166 | 167 | if (/^[\],:{}\s]*$/.test(filtered)) { 168 | /*jshint evil: true */ 169 | return eval('(' + str + ')'); 170 | } 171 | throw new SyntaxError('Error parsing JSON, source is not valid.'); 172 | }; 173 | 174 | /** 175 | * jQuery.quoteString 176 | * Returns a string-repr of a string, escaping quotes intelligently. 177 | * Mostly a support function for toJSON. 178 | * Examples: 179 | * >>> jQuery.quoteString('apple') 180 | * "apple" 181 | * 182 | * >>> jQuery.quoteString('"Where are we going?", she asked.') 183 | * "\"Where are we going?\", she asked." 184 | */ 185 | $.quoteString = function (str) { 186 | if (str.match(escape)) { 187 | return '"' + str.replace(escape, function (a) { 188 | var c = meta[a]; 189 | if (typeof c === 'string') { 190 | return c; 191 | } 192 | c = a.charCodeAt(); 193 | return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); 194 | }) + '"'; 195 | } 196 | return '"' + str + '"'; 197 | }; 198 | 199 | }(jQuery)); 200 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/js/main.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | var JSONRPCClient; ///< The core JSONRPC WebSocket client. 26 | 27 | function addError(error) { 28 | console.log(error); 29 | } 30 | 31 | function onWebSocketOpen(ws) { 32 | console.log("on open"); 33 | console.log(ws); 34 | } 35 | 36 | function onWebSocketMessage(evt) { 37 | console.log("on message:"); 38 | console.log(evt.data); 39 | } 40 | 41 | function onWebSocketClose() { 42 | console.log("on close"); 43 | } 44 | 45 | function onWebSocketError() { 46 | console.log("on error"); 47 | } 48 | 49 | function initializeButtons() { 50 | $('#get-text').on('click', function() { 51 | var $this = $(this); 52 | JSONRPCClient.call('get-text', 53 | null, 54 | function(result) { 55 | $('#text-to-recieve').val(result); 56 | }, 57 | function(error) { 58 | addError(error); 59 | }); 60 | }); 61 | 62 | 63 | $('#set-text').on('click', function() { 64 | var $this = $(this); 65 | JSONRPCClient.call('set-text', 66 | $('#text-to-send').val(), 67 | function(result) {}, 68 | function(error) { 69 | addError(error); 70 | }); 71 | }); 72 | 73 | 74 | $('#ping').on('click', function() { 75 | console.log("pinging"); 76 | var $this = $(this); 77 | JSONRPCClient.notify('ping'); 78 | }); 79 | 80 | 81 | $('#pong').on('click', function() { 82 | console.log("poinging"); 83 | var $this = $(this); 84 | JSONRPCClient.notify('pong'); 85 | }); 86 | } 87 | 88 | $(document).ready(function() { 89 | // Initialize our JSONRPCClient 90 | JSONRPCClient = new $.JsonRpcClient({ 91 | ajaxUrl: getDefaultPostURL(), 92 | socketUrl: getDefaultWebSocketURL(), // get a websocket for the localhost 93 | onmessage: onWebSocketMessage, 94 | onopen: onWebSocketOpen, 95 | onclose: onWebSocketClose, 96 | onerror: onWebSocketError 97 | }); 98 | 99 | initializeButtons(); 100 | 101 | }); -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/js/ofxHTTP.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | // ofxHTTP ///////////////////////////////////////////////////////////////////// 26 | 27 | // function ofPixelHandler() 28 | // { 29 | // var CMD_PIXELS = "SET_PIXELS"; 30 | 31 | // var OF_PIXELS_MONO = 0; 32 | // var OF_PIXELS_RGB = 1; 33 | // var OF_PIXELS_RGBA = 2; 34 | // var OF_PIXELS_BGRA = 3; 35 | // var OF_PIXELS_RGB565 = 4; 36 | 37 | // var PIXELS_DATA_TYPE_ARRAY_BUFFER = 0; 38 | // var PIXELS_DATA_TYPE_BLOB = 1; 39 | 40 | // var _bIsWaitingForPixels = false; 41 | // var _dataType = PIXELS_DATA_TYPE_ARRAY_BUFFER; 42 | // var _type = OF_PIXELS_RGBA; 43 | // var _width = 0; 44 | // var _height = 0; 45 | // var _destination = ""; 46 | 47 | // } 48 | 49 | // ofPixelHandler.prototype = function() 50 | // { 51 | // isWaitingForPixels: function() 52 | // { 53 | // return this._bIsWaitingForPixels; 54 | // }, 55 | // getPixelsDataType: function() 56 | // { 57 | // return this._pixelsDataType; 58 | // }, 59 | // getPixelsType: function() 60 | // { 61 | // return this._pixelsType; 62 | // }, 63 | // getWidth: function() 64 | // { 65 | // return this._width; 66 | // }, 67 | // getHeight: function() 68 | // { 69 | // return this._height; 70 | // } 71 | // getDestination: function() 72 | // { 73 | // return this._destination; 74 | // } 75 | // handleMessage: function(message) 76 | // { 77 | 78 | 79 | // return false; 80 | 81 | // return true; 82 | // } 83 | 84 | // } 85 | 86 | //------------------------------------------------------------------------------ 87 | function ofxHTTPBasicWebSocketClient(supportedProtocols) 88 | { 89 | var _self = this; 90 | 91 | var _ws = null; // WebSocket 92 | var _wsDataType = "binary"; 93 | var _customPath = ""; 94 | var _suppotedSubProtocols = supportedProtocols || []; 95 | var _keepAliveInterval = 15000; // milliseconds 96 | var _keepAliveTimeout = null; // set with setTimeout() 97 | var _retryConnectTimer = null; // set with setInterval() 98 | var _retryConnectInterval = 5000; // milliseconds 99 | var _bIsRetryingConnect = false; // are we in the process of retrying 100 | var _maxConnectRetries = 10; // we will allow this many retries 101 | var _numConnectRetries = 0; // how many times have we retried to connect 102 | 103 | var _commandCallbacks = new Object(); 104 | 105 | var _sequenceReceived = 0; 106 | var _sequenceTransmited = 0; 107 | 108 | var _JSONRPClient = new $.JsonRpcClient({ 109 | getSocket: function() { 110 | return _ws; 111 | }, 112 | onmessage: function(evt) { 113 | _onMessage(evt); 114 | } 115 | }); 116 | 117 | //-------------------------------------------------------------------------- 118 | 119 | 120 | //-------------------------------------------------------------------------- 121 | var _onUpdateMessage = function(message) 122 | { 123 | ofLogNotice("onMessageUpdate"); 124 | } 125 | 126 | //-------------------------------------------------------------------------- 127 | var _onUpdateStatus = function(status) 128 | { 129 | ofLogNotice("onStatusUpdate"); 130 | } 131 | 132 | //-------------------------------------------------------------------------- 133 | var _sendKeepAlive = function() 134 | { 135 | ofLogNotice("sendKeepAlive"); 136 | } 137 | 138 | //-------------------------------------------------------------------------- 139 | var _onOpen = function(evt) 140 | { 141 | ofLogNotice("onOpen"); 142 | } 143 | 144 | //-------------------------------------------------------------------------- 145 | var _onMessage = function(evt) 146 | { 147 | ofLogNotice("onMessage " + evt.data); 148 | } 149 | 150 | //-------------------------------------------------------------------------- 151 | var _onClose = function(evt) 152 | { 153 | ofLogNotice("onClose"); 154 | } 155 | 156 | //-------------------------------------------------------------------------- 157 | var _onError = function(evt) 158 | { 159 | ofLogNotice("onError"); 160 | } 161 | 162 | //-------------------------------------------------------------------------- 163 | // make sure that the appropriate websocket scheme is used 164 | // i.e. ws:// or wss:// for secure connections 165 | this.getWebSocketURL = function() 166 | { 167 | // TODO : ws_host = window.location.href.replace(/(http|https)(:\/\/.*?)\//, 'ws$2'); 168 | var scheme; 169 | var url = document.URL; 170 | if(url.substring(0, 5) == "https") 171 | { 172 | scheme = "wss://"; 173 | url = url.substr(8); 174 | } 175 | else 176 | { 177 | scheme = "ws://"; 178 | 179 | if (url.substring(0, 4) == "http") 180 | { 181 | url = url.substr(7); 182 | } 183 | } 184 | 185 | url = url.split('/'); 186 | 187 | return scheme + url[0]; 188 | } 189 | 190 | //-------------------------------------------------------------------------- 191 | this.getWebSocketDataType = function() 192 | { 193 | return _wsDataType; 194 | } 195 | 196 | //-------------------------------------------------------------------------- 197 | this.getWebSocket = function() 198 | { 199 | return _ws; 200 | } 201 | 202 | //-------------------------------------------------------------------------- 203 | this.isConnected = function() 204 | { 205 | return _ws != null; 206 | } 207 | 208 | //-------------------------------------------------------------------------- 209 | this.getCustomPath = function() 210 | { 211 | return _customPath; 212 | } 213 | 214 | //-------------------------------------------------------------------------- 215 | this.setCustomPath = function(customPath) 216 | { 217 | _customPath = customPath; 218 | } 219 | 220 | //-------------------------------------------------------------------------- 221 | this.getKeepAliveInterval = function() 222 | { 223 | return _keepAliveInterval; 224 | } 225 | 226 | //-------------------------------------------------------------------------- 227 | this.setKeepAliveInterval = function(keepAliveInterval) 228 | { 229 | _keepAliveInterval = keepAliveInterval; 230 | } 231 | 232 | //-------------------------------------------------------------------------- 233 | this.getSupportedSubProtocols = function() 234 | { 235 | return _suppotedSubProtocols; 236 | } 237 | 238 | //-------------------------------------------------------------------------- 239 | this.getRetryConnectInterval = function() 240 | { 241 | return _retryConnectInterval; 242 | } 243 | 244 | //-------------------------------------------------------------------------- 245 | this.setRetryConnectInterval = function(retryConnectInterval) 246 | { 247 | _retryConnectInterval = retryConnectInterval; 248 | } 249 | 250 | //-------------------------------------------------------------------------- 251 | this.isRetryingConnect = function() 252 | { 253 | return _isRetryingConnect; 254 | } 255 | 256 | //-------------------------------------------------------------------------- 257 | this.getMaxConnectRetries = function() 258 | { 259 | return _maxConnectRetries; 260 | } 261 | 262 | //-------------------------------------------------------------------------- 263 | this.setMaxConnectRetries = function(maxConnectRetries) 264 | { 265 | _maxConnectRetries = maxConnectRetries; 266 | } 267 | 268 | //-------------------------------------------------------------------------- 269 | this.setBinaryType = function(binaryType) 270 | { 271 | if(_self.isConnected()) 272 | { 273 | if(binaryType == "blob" || 274 | binaryType == "arraybuffer") 275 | { 276 | _ws.binaryType = binaryType; 277 | } 278 | else 279 | { 280 | ofLogError("Unknown binaryType: " + binaryType); 281 | } 282 | } 283 | else 284 | { 285 | ofLogError("WebSocket has not been initialized. Please call connect() first."); 286 | } 287 | } 288 | 289 | //-------------------------------------------------------------------------- 290 | this.setOnOpen = function(fn) 291 | { 292 | _onOpen = fn; 293 | } 294 | 295 | //-------------------------------------------------------------------------- 296 | this.setOnMessage = function(fn) 297 | { 298 | _onMessage = fn; 299 | } 300 | 301 | //-------------------------------------------------------------------------- 302 | this.setOnClose = function(fn) 303 | { 304 | _onClose = fn; 305 | } 306 | 307 | //-------------------------------------------------------------------------- 308 | this.setOnError = function(fn) 309 | { 310 | _onError = fn; 311 | } 312 | 313 | //-------------------------------------------------------------------------- 314 | this.getBufferedAmount = function() 315 | { 316 | if(_self.isConnected()) 317 | { 318 | return _ws.bufferedAmount; 319 | } 320 | else 321 | { 322 | ofLogError("WebSocket has not been initialized. Please call connect() first."); 323 | return -1; 324 | } 325 | } 326 | 327 | //-------------------------------------------------------------------------- 328 | this.connect = function() 329 | { 330 | if("WebSocket" in window) 331 | { 332 | try 333 | { 334 | _ws = new WebSocket(_self.getWebSocketURL(), 335 | _self.getSupportedSubProtocols()); 336 | 337 | _ws.onopen = function(evt) 338 | { 339 | _onOpen(evt); // our event 340 | 341 | _retryConnectTimer = setInterval( 342 | function() 343 | { 344 | _sendKeepAlive(); 345 | }, 346 | _self.getKeepAliveInterval() 347 | ); 348 | } 349 | 350 | _ws.onmessage = function(evt) 351 | { 352 | _onMessage(evt); 353 | } 354 | 355 | _ws.onclose = function(evt) 356 | { 357 | clearInterval(_retryConnectTimer); 358 | 359 | if(!evt.wasClean || evt.code == 1006 /* 1006 == abnormal closure */) 360 | { 361 | if(_self.getSupportedSubProtocols().length > 0 && 362 | _self.getSupportedSubProtocols().hasObject(evt.target.protocol)) 363 | { 364 | ofLogError("None of the proposed subprotocols [" + _self.getSupportedSubProtocols() + "] were supported by the server."); 365 | } 366 | else 367 | { 368 | ofLogError("Closed for an unknown reason, code: " + evt.code); 369 | } 370 | } 371 | 372 | _onClose(evt); // our event 373 | } 374 | 375 | _ws.onerror = function(evt) 376 | { 377 | _onError(evt); 378 | } 379 | 380 | } catch(exception) { 381 | ofLogError(exception); 382 | } 383 | } 384 | else 385 | { 386 | alert("This browser does not support WebSockets. Please upgrade your browser."); 387 | } 388 | } 389 | 390 | //-------------------------------------------------------------------------- 391 | this.disconnect = function() 392 | { 393 | if(_self.isConnected()) 394 | { 395 | window.clearInterval(_keepAliveTimeout); 396 | _ws.close(); 397 | _ws = null; 398 | } 399 | else 400 | { 401 | ofLogError("WebSocket has not been initialized. Please call connect first."); 402 | } 403 | } 404 | 405 | //-------------------------------------------------------------------------- 406 | this.send = function(val) 407 | { 408 | // this will be reset each time 409 | window.clearInterval(_keepAliveTimeout); 410 | _keepAliveTimeout = window.setInterval(_sendKeepAlive, 411 | _keepAliveInterval); 412 | 413 | // lastSendTime = now 414 | _ws.send(val); 415 | 416 | ofLogVerbose("Sent " + val); 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /example_no_window/bin/data/DocumentRoot/js/ofxUtils.js: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 3 | // Copyright (c) 2009-2013 Christopher Baker 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | // ============================================================================= 24 | 25 | // HELPER ////////////////////////////////////////////////////////////////////// 26 | Array.prototype.hasObject = ( 27 | !Array.indexOf ? function (o) { 28 | var l = this.length + 1; 29 | while (l -= 1) { 30 | if (this[l - 1] === o) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } : function (o) { 36 | return (this.indexOf(o) !== -1); 37 | } 38 | ); 39 | 40 | // LOGGING ///////////////////////////////////////////////////////////////////// 41 | var OF_LOG_VERBOSE = 0; 42 | var OF_LOG_NOTICE = 1; 43 | var OF_LOG_WARNING = 2; 44 | var OF_LOG_ERROR = 3; 45 | var OF_LOG_FATAL_ERROR = 4; 46 | var OF_LOG_SILENT = 5; 47 | 48 | var logLevel = OF_LOG_VERBOSE; 49 | 50 | function ofGetLogLevelName(_logLevel) 51 | { 52 | switch(_logLevel) 53 | { 54 | case OF_LOG_VERBOSE: 55 | return "OF_LOG_VERBOSE"; 56 | case OF_LOG_NOTICE: 57 | return "OF_LOG_NOTICE"; 58 | case OF_LOG_WARNING: 59 | return "OF_LOG_WARNING"; 60 | case OF_LOG_ERROR: 61 | return "OF_LOG_ERROR"; 62 | case OF_LOG_FATAL_ERROR: 63 | return "OF_LOG_FATAL_ERROR"; 64 | case OF_LOG_SILENT: 65 | return "OF_LOG_SILENT"; 66 | default: 67 | return "UNKNOWN_LOG_LEVEL"; 68 | } 69 | } 70 | 71 | function ofGetLogLevel() 72 | { 73 | return logLevel; 74 | } 75 | 76 | function ofSetLogLevel(_logLevel) 77 | { 78 | logLevel = _logLevel; 79 | } 80 | 81 | function ofLog(logLevel,val) 82 | { 83 | if(logLevel >= ofGetLogLevel()) 84 | { 85 | console.log(val); 86 | } 87 | } 88 | 89 | function ofLogVerbose(_message) 90 | { 91 | ofLog(self.OF_LOG_VERBOSE, _message); 92 | } 93 | 94 | function ofLogNotice(_message) 95 | { 96 | ofLog(self.OF_LOG_NOTICE, _message); 97 | } 98 | 99 | function ofLogWarning(_message) 100 | { 101 | ofLog(self.OF_LOG_WARNING, _message); 102 | } 103 | 104 | function ofLogError(_message) 105 | { 106 | ofLog(self.OF_LOG_ERROR, _message); 107 | } 108 | 109 | function ofLogFatalError(_message) 110 | { 111 | ofLog(self.OF_LOG_FATAL_ERROR, _message); 112 | } 113 | 114 | function ofLogSilent(_message) 115 | { 116 | ofLog(self.OF_LOG_SILENT, _message); 117 | } 118 | 119 | // UTILITIES /////////////////////////////////////////////////////////////////// 120 | 121 | function ofClamp(val,max,min) 122 | { 123 | return (val < min ? max : (val > min ? min : val)); 124 | } 125 | 126 | 127 | //-------------------------------------------------------------------------- 128 | // make sure that the appropriate websocket scheme is used 129 | // i.e. ws:// or wss:// for secure connections 130 | function getDefaultWebSocketURL() 131 | { 132 | var scheme; 133 | var url = document.URL; 134 | if(url.substring(0, 5) == "https") 135 | { 136 | scheme = "wss://"; 137 | url = url.substr(8); 138 | } 139 | else 140 | { 141 | scheme = "ws://"; 142 | 143 | if (url.substring(0, 4) == "http") 144 | { 145 | url = url.substr(7); 146 | } 147 | } 148 | 149 | url = url.split('/'); 150 | 151 | return scheme + url[0]; 152 | } 153 | 154 | //-------------------------------------------------------------------------- 155 | function getDefaultPostURL() 156 | { 157 | return document.URL + "post"; 158 | } 159 | -------------------------------------------------------------------------------- /example_no_window/bin/data/media/ipsum.txt: -------------------------------------------------------------------------------- 1 | Ethnic viral hoodie literally Pinterest, Marfa sriracha. Shabby chic food truck chia yr skateboard single-origin coffee kogi, bicycle rights Shoreditch next level flannel. Try-hard DIY gastropub small batch, ethical post-ironic Schlitz ennui cornhole aesthetic. Organic swag master cleanse +1 cred, disrupt irony American Apparel photo booth freegan normcore 3 wolf moon Truffaut food truck viral. Slow-carb ethnic roof party craft beer. Ethical blog pug semiotics irony readymade, banh mi authentic selfies. Before they sold out letterpress Etsy four loko keffiyeh, sustainable drinking vinegar farm-to-table small batch McSweeney's ethnic direct trade fap. 2 | 3 | Try-hard Neutra quinoa mixtape fanny pack, Austin small batch chambray meh Etsy occupy retro. Cornhole Truffaut fingerstache, tofu deep v shabby chic crucifix YOLO Schlitz. Truffaut tote bag mixtape photo booth master cleanse. Artisan PBR&B crucifix VHS. Mumblecore semiotics small batch Carles Thundercats butcher. Meh wayfarers food truck, master cleanse +1 banh mi scenester distillery Odd Future cred XOXO asymmetrical Blue Bottle. Trust fund wolf fanny pack, twee banjo XOXO McSweeney's typewriter Cosby sweater flexitarian. 4 | 5 | Wolf chambray four loko, single-origin coffee master cleanse whatever Odd Future. Literally farm-to-table aesthetic Wes Anderson VHS fanny pack fixie, food truck Echo Park Tonx Pitchfork normcore four loko lomo mumblecore. XOXO Pinterest cardigan raw denim sartorial, cliche Odd Future. Chillwave plaid fap cliche try-hard, locavore flexitarian Wes Anderson slow-carb. Stumptown Truffaut next level, butcher biodiesel pork belly Bushwick selfies twee Pinterest fap. Irony cornhole freegan small batch ethnic. DIY Schlitz fixie mustache actually Intelligentsia. 6 | 7 | Banksy Williamsburg sriracha salvia selfies, biodiesel plaid Godard single-origin coffee ethical XOXO banh mi seitan Portland 90's. Hella gentrify photo booth wolf readymade fingerstache, post-ironic church-key Bushwick cliche food truck actually bespoke literally Shoreditch. Occupy butcher cornhole, organic Brooklyn YOLO crucifix trust fund hella sustainable blog ethical typewriter Marfa American Apparel. Yr cray street art Kickstarter you probably haven't heard of them. Ethnic ugh sartorial chillwave Thundercats, tote bag Carles sustainable gentrify VHS distillery slow-carb Bushwick Odd Future. Quinoa kogi XOXO you probably haven't heard of them, lo-fi master cleanse mlkshk raw denim chillwave chia try-hard sartorial fixie leggings ethnic. Semiotics readymade cred church-key iPhone wolf Tonx organic Cosby sweater, stumptown Banksy pickled selvage drinking vinegar direct trade. -------------------------------------------------------------------------------- /example_no_window/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofApp.h" 9 | #include "ofAppNoWindow.h" 10 | 11 | 12 | int main() 13 | { 14 | ofAppNoWindow window; 15 | ofSetupOpenGL(&window, 0, 0, OF_WINDOW); 16 | return ofRunApp(std::make_shared()); 17 | } 18 | -------------------------------------------------------------------------------- /example_no_window/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofApp.h" 9 | 10 | 11 | void ofApp::setup() 12 | { 13 | ofSetFrameRate(30); 14 | 15 | ofSetLogLevel(OF_LOG_VERBOSE); 16 | 17 | // Load test text. 18 | ipsum = ofBufferFromFile("media/ipsum.txt").getText(); 19 | 20 | ofx::HTTP::JSONRPCServerSettings settings; 21 | settings.setPort(8197); 22 | 23 | // Initialize the server. 24 | server.setup(settings); 25 | 26 | // Register RPC methods. 27 | server.registerMethod("get-text", 28 | "Returns a random chunk of text to the client.", 29 | this, 30 | &ofApp::getText); 31 | 32 | server.registerMethod("set-text", 33 | "Sets text from the user.", 34 | this, 35 | &ofApp::setText); 36 | 37 | server.registerMethod("ping", 38 | "Send a JSONRPC Ping Notification", 39 | this, 40 | &ofApp::ping); 41 | 42 | server.registerMethod("pong", 43 | "Send a JSONRPC Pong Notification", 44 | this, 45 | &ofApp::pong); 46 | 47 | // Start the server. 48 | server.start(); 49 | 50 | // Launch a browser with the address of the server. 51 | ofLaunchBrowser(server.url()); 52 | } 53 | 54 | 55 | void ofApp::exit() 56 | { 57 | // Set the logger back to the default to make sure any 58 | // remaining messages are logged correctly. 59 | ofLogToConsole(); 60 | } 61 | 62 | 63 | void ofApp::ping() 64 | { 65 | ofLogVerbose("ofApp::ping") << "Ping'd"; 66 | } 67 | 68 | 69 | void ofApp::pong() 70 | { 71 | ofLogVerbose("ofApp::pong") << "Pong'd"; 72 | } 73 | 74 | 75 | void ofApp::getText(ofx::JSONRPC::MethodArgs& args) 76 | { 77 | // Set the result equal to the substring. 78 | args.result = getRandomText(); 79 | ofLogVerbose("ofApp::getText") << args.result.dump(4); 80 | } 81 | 82 | 83 | void ofApp::setText(ofx::JSONRPC::MethodArgs& args) 84 | { 85 | // Set the user text. 86 | setUserText(args.params); 87 | ofLogVerbose("ofApp::setText") << args.params.dump(4); 88 | } 89 | 90 | 91 | std::string ofApp::getRandomText() const 92 | { 93 | static const std::size_t LENGTH = 140; 94 | 95 | std::unique_lock lock(mutex); 96 | 97 | // Generate a random start index. 98 | std::size_t startIndex = std::size_t(ofRandom(ipsum.length())); 99 | 100 | // Ensure that the length is valid. 101 | std::size_t length = (startIndex + LENGTH) < ipsum.length() ? LENGTH : string::npos; 102 | 103 | // return the result equal to the substring. 104 | return ipsum.substr(startIndex, length); 105 | } 106 | 107 | 108 | std::string ofApp::getUserText() const 109 | { 110 | std::unique_lock lock(mutex); 111 | return userText; 112 | } 113 | 114 | 115 | void ofApp::setUserText(const std::string& text) 116 | { 117 | std::unique_lock lock(mutex); 118 | userText = text; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /example_no_window/src/ofApp.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include "ofMain.h" 12 | #include "ofxJSONRPC.h" 13 | 14 | 15 | class ofApp: public ofBaseApp 16 | { 17 | public: 18 | void setup() override; 19 | void exit() override; 20 | 21 | // Registered methods. 22 | void getText(ofx::JSONRPC::MethodArgs& args); 23 | void setText(ofx::JSONRPC::MethodArgs& args); 24 | 25 | // Register a no-argument notification method. 26 | void ping(); 27 | 28 | // Register a no-argument notification method. 29 | void pong(); 30 | 31 | /// \brief The server that handles the JSONRPC requests. 32 | ofx::HTTP::JSONRPCServer server; 33 | 34 | /// \brief Get a snippet of random text in a thread-safe way. 35 | /// \returns The snippet of random text. 36 | std::string getRandomText() const; 37 | 38 | /// \brief Get the user text in a thread-safe way. 39 | /// \returns The user text. 40 | std::string getUserText() const; 41 | 42 | /// \brief Set the user text in a thread-safe way. 43 | /// \param text the user text to set. 44 | void setUserText(const std::string& text); 45 | 46 | private: 47 | // A custom logging channel to mirror all log messages to the web clients. 48 | // WebSocketLoggerChannel::SharedPtr loggerChannel; 49 | 50 | // This piece of text might be modified by multiple client threads. 51 | // Thus we must use a mutex to protect it during multi-threaded access. 52 | std::string ipsum; 53 | 54 | // This piece of text might be modified by multiple client threads. 55 | // Thus we must use a mutex to protect it during multi-threaded access. 56 | std::string userText; 57 | 58 | // We use a mutex to protect any variables that can be 59 | // modified by multiple clients. In our case, userText must be protected. 60 | // We mark the mutex as mutable so that it can be used in const functions. 61 | mutable std::mutex mutex; 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /libs/ofxHTTP/include/ofx/HTTP/JSONRPCServer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | #pragma once 8 | 9 | 10 | #include "ofTypes.h" 11 | #include "ofx/HTTP/BaseServer.h" 12 | #include "ofx/HTTP/FileSystemRoute.h" 13 | #include "ofx/HTTP/PostRoute.h" 14 | #include "ofx/HTTP/WebSocketConnection.h" 15 | #include "ofx/HTTP/WebSocketRoute.h" 16 | #include "ofx/JSONRPC/MethodRegistry.h" 17 | 18 | 19 | namespace ofx { 20 | namespace HTTP { 21 | 22 | 23 | class JSONRPCServerSettings: public BaseServerSettings 24 | { 25 | public: 26 | FileSystemRouteSettings fileSystemRouteSettings; 27 | PostRouteSettings postRouteSettings; 28 | WebSocketRouteSettings webSocketRouteSettings; 29 | }; 30 | 31 | 32 | /// \brief A simple JSONRPCServer. 33 | /// 34 | /// This server can process JSONRPC calls submitted via WebSockets or 35 | /// POST requests. 36 | template 37 | class JSONRPCServer_: 38 | public BaseServer_, 39 | public JSONRPC::MethodRegistry 40 | { 41 | public: 42 | /// \brief A typedef for JSONRPCServerSettings. 43 | typedef JSONRPCServerSettings Settings; 44 | 45 | /// \brief Create a JSONRPCServer with settings. 46 | /// \param settings configure the JSONRPCServer with the given settings. 47 | JSONRPCServer_(const Settings& settings = Settings()); 48 | 49 | /// \brief Destroy the JSONRPCServer. 50 | virtual ~JSONRPCServer_(); 51 | 52 | /// \brief Set up the JSONRPCServer with the given settings. 53 | /// 54 | /// Settings will be applied on next server startup. 55 | /// \param settings configure the JSONRPCServer with the given settings. 56 | virtual void setup(const Settings& settings); 57 | 58 | /// \brief Get the PostRoute. 59 | /// \returns the PostRoute attached to this server. 60 | FileSystemRoute& fileSystemRoute(); 61 | 62 | /// \brief Get the PostRoute. 63 | /// \returns the PostRoute attached to this server. 64 | PostRoute& postRoute(); 65 | 66 | /// \brief Get the WebSocketRoute. 67 | /// \returns the WebSocketRoute attached to this server. 68 | WebSocketRoute& webSocketRoute(); 69 | 70 | bool onWebSocketOpenEvent(WebSocketOpenEventArgs& evt); 71 | bool onWebSocketCloseEvent(WebSocketCloseEventArgs& evt); 72 | bool onWebSocketFrameReceivedEvent(WebSocketFrameEventArgs& evt); 73 | bool onWebSocketFrameSentEvent(WebSocketFrameEventArgs& evt); 74 | bool onWebSocketErrorEvent(WebSocketErrorEventArgs& evt); 75 | 76 | bool onHTTPPostEvent(PostEventArgs& evt); 77 | bool onHTTPFormEvent(PostFormEventArgs& evt); 78 | bool onHTTPUploadEvent(PostUploadEventArgs& evt); 79 | 80 | protected: 81 | /// \brief The FileSystemRoute attached to this server. 82 | FileSystemRoute _fileSystemRoute; 83 | 84 | /// \brief The PostRoute attached to this server. 85 | PostRoute _postRoute; 86 | 87 | /// \brief The WebSocketRoute attached to this server. 88 | WebSocketRoute _webSocketRoute; 89 | 90 | }; 91 | 92 | 93 | typedef JSONRPCServer_ JSONRPCServer; 94 | 95 | 96 | template 97 | JSONRPCServer_::JSONRPCServer_(const Settings& settings): 98 | BaseServer_(settings), 99 | _fileSystemRoute(settings.fileSystemRouteSettings), 100 | _postRoute(settings.postRouteSettings), 101 | _webSocketRoute(settings.webSocketRouteSettings) 102 | { 103 | this->addRoute(&_fileSystemRoute); // #3 to test. 104 | this->addRoute(&_postRoute); // #2 to test. 105 | this->addRoute(&_webSocketRoute); // #1 to test. 106 | 107 | _postRoute.registerPostEvents(this); 108 | _webSocketRoute.registerWebSocketEvents(this); 109 | } 110 | 111 | 112 | template 113 | JSONRPCServer_::~JSONRPCServer_() 114 | { 115 | _webSocketRoute.unregisterWebSocketEvents(this); 116 | _postRoute.unregisterPostEvents(this); 117 | 118 | this->removeRoute(&_webSocketRoute); 119 | this->removeRoute(&_postRoute); 120 | this->removeRoute(&_fileSystemRoute); 121 | } 122 | 123 | 124 | template 125 | void JSONRPCServer_::setup(const Settings& settings) 126 | { 127 | BaseServer_::setup(settings); 128 | _fileSystemRoute.setup(settings.fileSystemRouteSettings); 129 | _postRoute.setup(settings.postRouteSettings); 130 | _webSocketRoute.setup(settings.webSocketRouteSettings); 131 | } 132 | 133 | 134 | template 135 | FileSystemRoute& JSONRPCServer_::fileSystemRoute() 136 | { 137 | return _fileSystemRoute; 138 | } 139 | 140 | 141 | template 142 | PostRoute& JSONRPCServer_::postRoute() 143 | { 144 | return _postRoute; 145 | } 146 | 147 | 148 | template 149 | WebSocketRoute& JSONRPCServer_::webSocketRoute() 150 | { 151 | return _webSocketRoute; 152 | } 153 | 154 | 155 | template 156 | bool JSONRPCServer_::onWebSocketOpenEvent(WebSocketOpenEventArgs& evt) 157 | { 158 | return false; // We did not attend to this event, so pass it along. 159 | } 160 | 161 | 162 | template 163 | bool JSONRPCServer_::onWebSocketCloseEvent(WebSocketCloseEventArgs& evt) 164 | { 165 | return false; // We did not attend to this event, so pass it along. 166 | } 167 | 168 | 169 | template 170 | bool JSONRPCServer_::onWebSocketFrameReceivedEvent(WebSocketFrameEventArgs& evt) 171 | { 172 | try 173 | { 174 | ofJson json = ofJson::parse(evt.frame().getText()); 175 | 176 | try 177 | { 178 | JSONRPC::Request request = JSONRPC::Request::fromJSON(evt, json); 179 | JSONRPC::Response response = processCall(this, request); 180 | 181 | if (response.hasId()) 182 | { 183 | evt.connection().sendFrame(response.toString()); 184 | } 185 | } 186 | catch (const Poco::InvalidArgumentException& exc) 187 | { 188 | JSONRPC::Response response(evt, 189 | ofJson(nullptr), // null value is required when parse exceptions 190 | JSONRPC::Error(JSONRPC::Errors::RPC_ERROR_INVALID_PARAMETERS)); 191 | 192 | evt.connection().sendFrame(response.toString()); 193 | } 194 | catch (const Poco::Exception& exc) 195 | { 196 | JSONRPC::Response response(evt, 197 | ofJson(nullptr), // null value is required when parse exceptions 198 | JSONRPC::Error(JSONRPC::Errors::RPC_ERROR_INTERNAL_ERROR)); 199 | 200 | evt.connection().sendFrame(response.toString()); 201 | } 202 | 203 | return true; // We attended to the event, so consume it. 204 | 205 | } 206 | catch (const std::invalid_argument& exc) 207 | { 208 | ofLogVerbose("JSONRPCServer::onWebSocketFrameReceivedEvent") << "Could not parse as JSON: " << exc.what(); 209 | ofLogVerbose("JSONRPCServer::onWebSocketFrameReceivedEvent") << evt.frame().getText(); 210 | return false; // We did not attend to this event, so pass it along. 211 | } 212 | } 213 | 214 | 215 | template 216 | bool JSONRPCServer_::onWebSocketFrameSentEvent(WebSocketFrameEventArgs& evt) 217 | { 218 | return false; // We did not attend to this event, so pass it along. 219 | } 220 | 221 | 222 | template 223 | bool JSONRPCServer_::onWebSocketErrorEvent(WebSocketErrorEventArgs& evt) 224 | { 225 | return false; // We did not attend to this event, so pass it along. 226 | } 227 | 228 | 229 | template 230 | bool JSONRPCServer_::onHTTPFormEvent(PostFormEventArgs& args) 231 | { 232 | ofLogVerbose("JSONRPCServer::onHTTPFormEvent") << ""; 233 | return false; // We did not attend to this event, so pass it along. 234 | } 235 | 236 | 237 | template 238 | bool JSONRPCServer_::onHTTPPostEvent(PostEventArgs& args) 239 | { 240 | try 241 | { 242 | ofJson json = ofJson::parse(args.getBuffer().getText()); 243 | 244 | try 245 | { 246 | JSONRPC::Request request = JSONRPC::Request::fromJSON(args, json); 247 | JSONRPC::Response response = processCall(this, request); 248 | 249 | if (response.hasId()) 250 | { 251 | std::string buffer = response.toString(); 252 | args.response().sendBuffer(buffer.c_str(), buffer.length()); 253 | } 254 | } 255 | catch (Poco::Exception& exc) 256 | { 257 | JSONRPC::Response response(args, 258 | ofJson(nullptr), // null value is required when parse exceptions. 259 | JSONRPC::Error(JSONRPC::Errors::RPC_ERROR_METHOD_NOT_FOUND)); 260 | 261 | std::string buffer = response.toString(); 262 | args.response().sendBuffer(buffer.c_str(), buffer.length()); 263 | } 264 | 265 | return true; // We attended to the event, so consume it. 266 | } 267 | catch (const std::invalid_argument& exc) 268 | { 269 | ofLogVerbose("JSONRPCServer::onHTTPPostEvent") << "Could not parse as JSON: " << exc.what(); 270 | ofLogVerbose("JSONRPCServer::onHTTPPostEvent") << args.getBuffer().getText(); 271 | 272 | return false; // We did not attend to this event, so pass it along. 273 | } 274 | } 275 | 276 | 277 | template 278 | bool JSONRPCServer_::onHTTPUploadEvent(PostUploadEventArgs& args) 279 | { 280 | std::string stateString = ""; 281 | 282 | switch (args.getState()) 283 | { 284 | case HTTP::PostUploadEventArgs::UPLOAD_STARTING: 285 | stateString = "STARTING"; 286 | break; 287 | case HTTP::PostUploadEventArgs::UPLOAD_PROGRESS: 288 | stateString = "PROGRESS"; 289 | break; 290 | case HTTP::PostUploadEventArgs::UPLOAD_FINISHED: 291 | stateString = "FINISHED"; 292 | break; 293 | } 294 | 295 | return false; // We did not attend to this event, so pass it along. 296 | } 297 | 298 | 299 | 300 | 301 | } } // namespace ofx::HTTP 302 | -------------------------------------------------------------------------------- /libs/ofxHTTP/src/JSONRPCServer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | #include "ofx/HTTP/JSONRPCServer.h" 8 | 9 | 10 | namespace ofx { 11 | namespace HTTP { 12 | 13 | 14 | } } // namespace ofx::HTTP 15 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/BaseMessage.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include "ofJson.h" 13 | #include "ofx/HTTP/ServerEvents.h" 14 | 15 | 16 | namespace ofx { 17 | namespace JSONRPC { 18 | 19 | 20 | /// \brief A BaseMessage is a base class for both Request and Response objects. 21 | class BaseMessage: public HTTP::ServerEventArgs 22 | { 23 | public: 24 | /// \brief Create a BaseMessage. 25 | BaseMessage(HTTP::ServerEventArgs& evt, 26 | const ofJson& id); 27 | 28 | /// \brief Destroy the BaseMessage. 29 | virtual ~BaseMessage(); 30 | 31 | /// \returns the message ID. 32 | const ofJson& id() const; 33 | OF_DEPRECATED_MSG("Use id() instead.", ofJson getId() const); 34 | 35 | /// \return true iff the ID is not null. 36 | bool hasId() const; 37 | 38 | protected: 39 | /// \brief The id of the remote call. 40 | ofJson _id; 41 | 42 | /// \brief JSONRPC tag. 43 | static const std::string PROTOCOL_VERSION_TAG; 44 | 45 | /// \brief The JSONRPC version. 46 | static const std::string PROTOCOL_VERSION; 47 | 48 | /// \brief ID tag. 49 | static const std::string ID_TAG; 50 | 51 | }; 52 | 53 | 54 | } } // namespace ofx::JSONRPC 55 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/Error.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include 13 | #include "ofConstants.h" 14 | #include "ofJson.h" 15 | #include "ofx/JSONRPC/Errors.h" 16 | 17 | 18 | namespace ofx { 19 | namespace JSONRPC { 20 | 21 | 22 | /// \brief A JSONRPC 2.0 error object. 23 | /// \sa http://www.jsonrpc.org/specification 24 | class Error 25 | { 26 | public: 27 | /// \brief Create an Error. 28 | /// \note The code will be set to Errors::RPC_ERROR_NONE. 29 | Error(); 30 | 31 | /// \brief Create an Error. 32 | /// \param code is the error code. 33 | /// \note The error message will be queried based on the code. 34 | /// \note The data field will be left blank. 35 | explicit Error(int code); 36 | 37 | /// \brief Create an Error. 38 | /// \param code is the error code. 39 | /// \param message the error message. 40 | explicit Error(int code, const ofJson& data); 41 | 42 | /// \brief Create an Error. 43 | /// \param code is the error code. 44 | /// \param message the error message. 45 | /// \param data the error data. 46 | explicit Error(int code, const std::string& message, const ofJson& data); 47 | 48 | /// \brief Destroy the Error. 49 | virtual ~Error(); 50 | 51 | /// \returns the error code. 52 | int code() const; 53 | OF_DEPRECATED_MSG("Use code() instead.", int getCode() const); 54 | 55 | /// \returns the error message. 56 | const std::string& message() const; 57 | OF_DEPRECATED_MSG("Use message() instead.", std::string getMessage() const); 58 | 59 | /// \returns the data. 60 | /// \note The JSON data may be empty. 61 | const ofJson& data() const; 62 | OF_DEPRECATED_MSG("Use data() instead.", ofJson getData() const); 63 | 64 | /// \brief Serialize the Error object to JSON. 65 | /// \param error the Error object to serialize. 66 | /// \returns JSONRPC compatible JSON. 67 | static ofJson toJSON(const Error& error); 68 | 69 | /// \brief Deserialize the JSON to a Error object. 70 | /// \param json JSONRPC compatible JSON to deserialize. 71 | /// \returns the deserialized Error. 72 | /// \throws Poco::Exception if the JSON is not valid. 73 | static Error fromJSON(const ofJson& json); 74 | 75 | protected: 76 | /// \brief A Number that indicates the error type that occurred. 77 | /// \details This code MUST be an integer. 78 | int _code; 79 | 80 | /// \brief A String providing a short description of the error. 81 | /// \details The message SHOULD be limited to a concise single sentence. 82 | std::string _message; 83 | 84 | /// \brief A Json::Value that contains additional error info. 85 | /// 86 | /// This may be omitted. The value of this member is defined by the Server 87 | /// (e.g. detailed error information, nested errors etc.). 88 | ofJson _data; 89 | 90 | /// \brief Error code tag. 91 | static const std::string ERROR_CODE_TAG; 92 | 93 | /// \brief Error message tag. 94 | static const std::string ERROR_MESSAGE_TAG; 95 | 96 | /// \brief Error data tag. 97 | static const std::string ERROR_DATA_TAG; 98 | 99 | }; 100 | 101 | 102 | } } // namespace ofx::JSONRPC 103 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/Errors.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include "json.hpp" 13 | #include "Poco/Exception.h" 14 | 15 | 16 | namespace ofx { 17 | namespace JSONRPC { 18 | 19 | 20 | /// \brief JSONRPC 2.0 errors and exceptions. 21 | /// \sa http://www.jsonrpc.org/specification 22 | class Errors 23 | { 24 | public: 25 | /// \brief Get the error message for the given error code. 26 | /// \param code is the error code to search for. 27 | /// \returns a string containing the error string. If the error code 28 | /// is unknown, but in the range -32000 to -32099, 29 | /// "undefined server error" will be returned. Otherwise, 30 | /// "unknown error" will be returned. 31 | static std::string getErrorMessage(int code); 32 | 33 | /// \brief No Error. 34 | static const int RPC_ERROR_NONE; 35 | 36 | /// \brief Invalid Request. 37 | static const int RPC_ERROR_INVALID_REQUEST; 38 | 39 | /// \brief Method Not Found. 40 | static const int RPC_ERROR_METHOD_NOT_FOUND; 41 | 42 | /// \brief Invalid Parameters. 43 | static const int RPC_ERROR_INVALID_PARAMETERS; 44 | 45 | /// \brief Internal Error. 46 | static const int RPC_ERROR_INTERNAL_ERROR; 47 | 48 | /// \brief Parse Error. 49 | static const int RPC_ERROR_PARSE; 50 | 51 | }; 52 | 53 | 54 | POCO_DECLARE_EXCEPTION_CODE(, 55 | JSONRPCException, 56 | Poco::Exception, 57 | Errors::RPC_ERROR_INTERNAL_ERROR) 58 | 59 | POCO_DECLARE_EXCEPTION_CODE(, 60 | InvalidRequestException, 61 | JSONRPCException, 62 | Errors::RPC_ERROR_INVALID_REQUEST) 63 | 64 | POCO_DECLARE_EXCEPTION_CODE(, 65 | MethodNotFoundException, 66 | JSONRPCException, 67 | Errors::RPC_ERROR_METHOD_NOT_FOUND) 68 | 69 | POCO_DECLARE_EXCEPTION_CODE(, 70 | InvalidParametersException, 71 | JSONRPCException, 72 | Errors::RPC_ERROR_INVALID_PARAMETERS) 73 | 74 | POCO_DECLARE_EXCEPTION_CODE(, 75 | InternalErrorException, 76 | JSONRPCException, 77 | Errors::RPC_ERROR_INTERNAL_ERROR) 78 | 79 | POCO_DECLARE_EXCEPTION_CODE(, 80 | ParseException, 81 | JSONRPCException, 82 | Errors::RPC_ERROR_PARSE) 83 | 84 | 85 | } } // namespace ofx::JSONRPC 86 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/JSONRPC.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | /// \namespace ofx 12 | /// \brief openFrameworks Extended 13 | /// \sa http://openframeworks.cc 14 | /// \sa http://ofxaddons.com 15 | namespace ofx 16 | { 17 | // \namespace JSONRPC 18 | // \brief JSONRPC is a stateless light-weight remote procedure call protocol. 19 | // \sa http://www.jsonrpc.org/specification 20 | namespace JSONRPC 21 | { 22 | 23 | 24 | } } // namespace ofx::JSONRPC 25 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/JSONRPCUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include "json.hpp" 13 | #include "Poco/UUID.h" 14 | #include "ofx/JSONRPC/Errors.h" 15 | #include "ofx/JSONRPC/Response.h" 16 | #include "ofx/JSONRPC/Request.h" 17 | 18 | 19 | namespace ofx { 20 | namespace JSONRPC { 21 | 22 | 23 | /// \brief A collection of utilities for JSONRPC. 24 | class JSONRPCUtils 25 | { 26 | public: 27 | /// \brief Convert JSON values to a raw string representation. 28 | /// \param json The JSON value to convert. 29 | /// \param styled If true, the raw string will be indented 30 | /// with returns and thus easier to read (aka pretty print). 31 | /// \returns A std::string representation of the JSON. 32 | static std::string toString(const ofJson& json, bool styled = false); 33 | 34 | /// \brief Determine whether the given json has the named key. 35 | /// \param json The json to check. 36 | /// \param key The key to check. 37 | /// \returns true if the given key exists. 38 | static bool hasKey(const ofJson& json, const std::string& key); 39 | 40 | /// \brief Determine whether the given json has the named key of a certain type. 41 | /// \param json The json to check. 42 | /// \param key The key to check. 43 | /// \param type The data type to check. 44 | /// \returns true if the given key exists. 45 | static bool hasKeyOfType(const ofJson& json, 46 | const std::string& key, 47 | ofJson::value_t type); 48 | 49 | /// \brief Determine whether the given json has the named key of string type. 50 | /// \param json The json to check. 51 | /// \param key The key to check. 52 | /// \returns true if the given key exists. 53 | static bool hasStringKey(const ofJson& json, 54 | const std::string& key); 55 | 56 | /// \brief Determine whether the given json has the named key of integer type. 57 | /// \param json The json to check. 58 | /// \param key The key to check. 59 | /// \returns true if the given key exists. 60 | static bool hasIntegerKey(const ofJson& json, 61 | const std::string& key); 62 | 63 | }; 64 | 65 | 66 | } } // namespace ofx::JSONRPC 67 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/Method.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include "json.hpp" 12 | #include "Poco/Exception.h" 13 | #include "ofx/JSONRPC/Error.h" 14 | #include "ofx/JSONRPC/MethodArgs.h" 15 | 16 | 17 | namespace ofx { 18 | namespace JSONRPC { 19 | 20 | 21 | /// \brief A method callback class for registering JSONRPC methods. 22 | template 23 | class Method_ 24 | { 25 | public: 26 | /// \brief Create a Method Callback 27 | /// \param name The method's name. 28 | /// \param description A description of the method's functionality. 29 | Method_(const std::string& name, 30 | const ofJson& description = nullptr); 31 | 32 | /// \brief Destory the Method. 33 | virtual ~Method_(); 34 | 35 | /// \brief Get the method name. 36 | /// \returns the name of the method. 37 | const std::string& name() const; 38 | OF_DEPRECATED_MSG("Use name() instead.", std::string getName() const); 39 | 40 | /// \brief Get the method's description. 41 | /// \returns the name of the method. 42 | const ofJson& description() const; 43 | OF_DEPRECATED_MSG("Use description() instead.", ofJson getDescription() const); 44 | 45 | /// \brief The public event available for subscription. 46 | EventType event; 47 | 48 | private: 49 | /// \brief The method's name. 50 | std::string _name; 51 | 52 | /// \brief A description of the method's functionality. 53 | ofJson _description; 54 | 55 | }; 56 | 57 | 58 | typedef Method_ > Method; 59 | typedef Method_ > NoArgMethod; 60 | 61 | 62 | template 63 | Method_::Method_(const std::string& name, 64 | const ofJson& description): 65 | _name(name), 66 | _description(description) 67 | { 68 | } 69 | 70 | 71 | template 72 | inline Method_::~Method_() 73 | { 74 | } 75 | 76 | 77 | template 78 | inline const std::string& Method_::name() const 79 | { 80 | return _name; 81 | } 82 | 83 | 84 | template 85 | inline std::string Method_::getName() const 86 | { 87 | return _name; 88 | } 89 | 90 | 91 | template 92 | inline const ofJson& Method_::description() const 93 | { 94 | return _description; 95 | } 96 | 97 | 98 | template 99 | inline ofJson Method_::getDescription() const 100 | { 101 | return _description; 102 | } 103 | 104 | 105 | } } // namespace ofx::JSONRPC 106 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/MethodArgs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include "ofx/HTTP/ServerEvents.h" 13 | #include "ofx/JSONRPC/JSONRPCUtils.h" 14 | 15 | 16 | namespace ofx { 17 | namespace JSONRPC { 18 | 19 | 20 | /// \brief A contain all arguments for an JSONRPC method call. 21 | /// 22 | /// Arguments include the Request parameters and either Results or an Error to 23 | /// be set if required. 24 | /// 25 | /// If the Error object is set to an error code other than RPC_ERROR_NONE, the 26 | /// Json::Value results will be ignored and the error will be returned to the 27 | /// caller. 28 | /// 29 | /// Usually, upon error, the user will throw one of the convenient 30 | /// child classes of JSONRPCException, which will be caught and an error 31 | /// response will be returned to the caller. But, in cases where data should 32 | /// be returned with the error response, the user must manually set the 33 | /// error message and return immediately. 34 | class MethodArgs: public HTTP::ServerEventArgs 35 | { 36 | public: 37 | /// \brief Create a MethodArgs with the given parameters. 38 | /// \param params The JSON contents of the JSONRPC request params. 39 | /// If there are no arguments provided, the params are null. 40 | MethodArgs(HTTP::ServerEventArgs&, 41 | const ofJson& params); 42 | 43 | /// \brief Destroy the MethodArgs. 44 | virtual ~MethodArgs(); 45 | 46 | /// \brief The JSON contents of the JSONRPC request params. 47 | const ofJson params; 48 | 49 | /// \brief The result to be returned, if required. 50 | ofJson result; 51 | 52 | /// \brief The error to be returned, if required. 53 | /// 54 | /// If the Error object is set to an error code other than RPC_ERROR_NONE, 55 | /// the Json::Value results will be ignored and the error will be returned 56 | /// to the caller. 57 | /// 58 | /// This can be used as an alternative to throwing an exception in the 59 | /// remote method. 60 | Error error; 61 | 62 | /// \brief Get the MethodArgs as a string. 63 | /// \param styled true if the output string should be pretty-print. 64 | /// \returns a raw json string of this MethodArgs 65 | std::string toString(bool styled = false) const; 66 | 67 | }; 68 | 69 | 70 | } } // namespace ofx::JSONRPC 71 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/MethodRegistry.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include 13 | #include "json.hpp" 14 | #include "ofEvents.h" 15 | #include "ofLog.h" 16 | #include "ofx/JSONRPC/Method.h" 17 | #include "ofx/JSONRPC/MethodArgs.h" 18 | #include "ofx/JSONRPC/Response.h" 19 | #include "ofx/JSONRPC/Request.h" 20 | 21 | 22 | namespace ofx { 23 | namespace JSONRPC { 24 | 25 | 26 | /// \brief A MethodRegistry is a thread-safe method callback manager. 27 | /// 28 | /// Additionally, a MethodRegistry is in charge of invoking methods by 29 | /// name using the method signature defined in Method. 30 | class MethodRegistry 31 | { 32 | public: 33 | /// \brief A typedef mapping method names to method descriptions. 34 | typedef std::map MethodDescriptionMap; 35 | 36 | /// \brief Create a MethodRegistry. 37 | MethodRegistry(); 38 | 39 | /// \brief Destroy the MethodRegistry. 40 | virtual ~MethodRegistry(); 41 | 42 | /// \brief Register a method callback. 43 | /// 44 | /// Each method needs a name, description, class and method. This method 45 | /// registers remote methods with the following signature: 46 | /// 47 | /// ~~~{.cpp} 48 | /// void ListenerClass::listenerMethod(const void* pSender, MethodArgs& args); 49 | /// ~~~ 50 | /// 51 | /// \param name The name of the class to be called by the client. 52 | /// \param description A JSON description of any information to 53 | /// advertise with this method. This might include a 54 | /// description of the functionality, the input / output 55 | /// arguments, expected values, etc. 56 | /// \param listener A pointer to the listener class. 57 | /// \param listenerMethod A pointer to the method to invoke. 58 | /// \param priority The priority of the event. 59 | template 60 | void registerMethod(const std::string& name, 61 | const ofJson& description, 62 | ListenerClass* listener, 63 | void (ListenerClass::*listenerMethod)(const void*, MethodArgs&), 64 | int priority = OF_EVENT_ORDER_AFTER_APP); 65 | 66 | /// \brief Register a method callback. 67 | /// 68 | /// Each method needs a name, description, class and method. This method 69 | /// registers remote methods with the following signature: 70 | /// 71 | /// ~~~{.cpp} 72 | /// void ListenerClass::listenerMethod(MethodArgs& args); 73 | /// ~~~ 74 | /// 75 | /// \param name The name of the class to be called by the client. 76 | /// \param description A JSON description of any information to 77 | /// advertise with this method. This might include a 78 | /// description of the functionality, the input / output 79 | /// arguments, expected values, etc. 80 | /// \param listener A pointer to the listener class. 81 | /// \param listenerMethod A pointer to the method to invoke. 82 | /// \param priority The priority of the event. 83 | template 84 | void registerMethod(const std::string& name, 85 | const ofJson& description, 86 | ListenerClass* listener, 87 | void (ListenerClass::*listenerMethod)(MethodArgs&), 88 | int priority = OF_EVENT_ORDER_AFTER_APP); 89 | 90 | /// \brief Register a no argument method callback. 91 | /// 92 | /// Each method needs a name, description, class and method. This method 93 | /// registers remote methods with the following signature: 94 | /// 95 | /// ~~~{.cpp} 96 | /// void ListenerClass::listenerMethod(const void* pSender); 97 | /// ~~~ 98 | /// 99 | /// \param name The name of the class to be called by the client. 100 | /// \param description A JSON description of any information to 101 | /// advertise with this method. This might include a 102 | /// description of the functionality, the input / output 103 | /// arguments, expected values, etc. 104 | /// \param listener A pointer to the listener class. 105 | /// \param listenerMethod A pointer to the method to invoke. 106 | /// \param priority The priority of the event. 107 | template 108 | void registerMethod(const std::string& name, 109 | const ofJson& description, 110 | ListenerClass* listener, 111 | void (ListenerClass::*listenerMethod)(const void*), 112 | int priority = OF_EVENT_ORDER_AFTER_APP); 113 | 114 | /// \brief Register a no argument method callback. 115 | /// 116 | /// Each method needs a name, description, class and method. This method 117 | /// registers remote methods with the following signature: 118 | /// 119 | /// ~~~{.cpp} 120 | /// void ListenerClass::listenerMethod(); 121 | /// ~~~ 122 | /// 123 | /// \param name The name of the class to be called by the client. 124 | /// \param description A JSON description of any information to 125 | /// advertise with this method. This might include a 126 | /// description of the functionality, the input / output 127 | /// arguments, expected values, etc. 128 | /// \param listener A pointer to the listener class. 129 | /// \param listenerMethod A pointer to the method to invoke. 130 | /// \param priority The priority of the event. 131 | template 132 | void registerMethod(const std::string& name, 133 | const ofJson& description, 134 | ListenerClass* listener, 135 | void (ListenerClass::*listenerMethod)(void), 136 | int priority = OF_EVENT_ORDER_AFTER_APP); 137 | 138 | /// \brief Unregister a method by name. 139 | /// \param method is the name of the method callback to be removed. 140 | /// \note If the given method does not exist, the unregister 141 | /// request will be ignored. 142 | void unregisterMethod(const std::string& method); 143 | 144 | /// \brief Process a Request. 145 | /// \param pSender A pointer to the sender. This might be a pointer 146 | /// to a session cookie or WebSocket connection. While not 147 | /// required, this pointer is useful for returning 148 | /// client-specific method results or responding updating 149 | /// the calling client's session information. The user is 150 | /// responsible for using this sender information in 151 | /// corresponding method callback. 152 | /// \param request The incoming Request from a client. 153 | /// \returns A success or error Response. 154 | Response processCall(const void* pSender, Request& request); 155 | 156 | /// \brief Process a Request. 157 | /// \param pSender A pointer to the sender. This might be a pointer 158 | /// to a session cookie or WebSocket connection. While not 159 | /// required, this pointer is useful for returning 160 | /// client-specific method results or responding updating 161 | /// the calling client's session information. The user is 162 | /// responsible for using this sender information in 163 | /// corresponding method callback. 164 | /// \param request The incoming Request from a client. 165 | void processNotification(const void* pSender, Request& request); 166 | 167 | /// \brief Query the registry for the given method. 168 | /// \param method the name of the method to find. 169 | /// \returns true iff the given method is in the registry. 170 | bool hasMethod(const std::string& method) const; 171 | 172 | /// \brief Get a list of all method names and their descriptions. 173 | /// \returns a MethodDescriptionMap containting a map of the 174 | /// method names and the method descriptions. 175 | MethodDescriptionMap methods() const; 176 | OF_DEPRECATED_MSG("Use methods() instead.", MethodDescriptionMap getMethods() const); 177 | 178 | protected: 179 | /// \brief A shared pointer typedef for methods; 180 | typedef std::shared_ptr SharedMethodPtr; 181 | 182 | /// \brief A shared pointer typedef for no argument methods; 183 | typedef std::shared_ptr SharedNoArgMethodPtr; 184 | 185 | /// \brief A method map. 186 | typedef std::map MethodMap; 187 | 188 | /// \brief A void no argument method map. 189 | typedef std::map NoArgMethodMap; 190 | 191 | /// \brief A method map iterator. 192 | typedef MethodMap::iterator MethodMapIter; 193 | 194 | /// \brief A no argument method map iterator. 195 | typedef NoArgMethodMap::iterator NoArgMethodMapIter; 196 | 197 | /// \brief Maps method names to their method pointers. 198 | MethodMap _methodMap; 199 | 200 | /// \brief Maps no argument method names to their method pointers. 201 | NoArgMethodMap _noArgMethodMap; 202 | 203 | /// \brief A mutext to ensure method map validity. 204 | mutable std::mutex _mutex; 205 | 206 | }; 207 | 208 | 209 | template 210 | void MethodRegistry::registerMethod(const std::string& name, 211 | const ofJson& description, 212 | ListenerClass* listener, 213 | void (ListenerClass::*listenerMethod)(const void*, MethodArgs&), 214 | int priority) 215 | { 216 | unregisterMethod(name); 217 | 218 | std::unique_lock lock(_mutex); 219 | _methodMap[name] = SharedMethodPtr(new Method(name, description)); 220 | _methodMap[name]->event.add(listener, listenerMethod, priority); 221 | } 222 | 223 | template 224 | void MethodRegistry::registerMethod(const std::string& name, 225 | const ofJson& description, 226 | ListenerClass* listener, 227 | void (ListenerClass::*listenerMethod)(MethodArgs&), 228 | int priority) 229 | { 230 | unregisterMethod(name); 231 | 232 | std::unique_lock lock(_mutex); 233 | _methodMap[name] = SharedMethodPtr(new Method(name, description)); 234 | _methodMap[name]->event.add(listener, listenerMethod, priority); 235 | } 236 | 237 | template 238 | void MethodRegistry::registerMethod(const std::string& name, 239 | const ofJson& description, 240 | ListenerClass* listener, 241 | void (ListenerClass::*listenerMethod)(const void*), 242 | int priority) 243 | { 244 | unregisterMethod(name); 245 | 246 | std::unique_lock lock(_mutex); 247 | _noArgMethodMap[name] = SharedNoArgMethodPtr(new NoArgMethod(name, description)); 248 | _noArgMethodMap[name]->event.add(listener, listenerMethod, priority); 249 | } 250 | 251 | template 252 | void MethodRegistry::registerMethod(const std::string& name, 253 | const ofJson& description, 254 | ListenerClass* listener, 255 | void (ListenerClass::*listenerMethod)(void), 256 | int priority) 257 | { 258 | unregisterMethod(name); 259 | 260 | std::unique_lock lock(_mutex); 261 | _noArgMethodMap[name] = SharedNoArgMethodPtr(new NoArgMethod(name, description)); 262 | _noArgMethodMap[name]->event.add(listener, listenerMethod, priority); 263 | } 264 | 265 | 266 | } } // namespace ofx::JSONRPC 267 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/Request.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include 13 | #include "json.hpp" 14 | #include "ofx/JSONRPC/Error.h" 15 | #include "ofx/JSONRPC/BaseMessage.h" 16 | 17 | 18 | namespace ofx { 19 | namespace JSONRPC { 20 | 21 | 22 | /// \brief A JSONRPC 2.0 Request. 23 | /// 24 | /// A Request has the following format: 25 | /// 26 | /// ~~~{.json} 27 | /// { 28 | /// "jsonrpc": "2.0", 29 | /// "method": "subtract", 30 | /// "params": { 31 | /// "subtrahend": 23, 32 | /// "minuend": 42 33 | /// }, 34 | /// "id": 3 35 | /// } 36 | /// ~~~ 37 | /// 38 | /// \sa http://www.jsonrpc.org/specification 39 | class Request: public BaseMessage 40 | { 41 | public: 42 | /// \brief Create a notification Request. 43 | /// \param evt The originating server event. 44 | /// \param method The method's name. 45 | Request(HTTP::ServerEventArgs& evt, 46 | const std::string& method); 47 | 48 | /// \brief Create a notification Request. 49 | /// \param evt The originating server event. 50 | /// \param method The method's name. 51 | /// \param parameters The parameters to pass to the method. 52 | Request(HTTP::ServerEventArgs& evt, 53 | const std::string& method, const ofJson& parameters); 54 | 55 | /// \brief Create a Request. 56 | /// \param evt The originating server event. 57 | /// \param id The transatction identification number. 58 | /// \param method The method's name. 59 | Request(HTTP::ServerEventArgs& evt, 60 | const ofJson& id, const std::string& method); 61 | 62 | /// \brief Create a Request. 63 | /// \param evt The originating server event. 64 | /// \param id The transatction identification number. 65 | /// \param method The method's name. 66 | /// \param parameters The parameters to pass to the method. 67 | Request(HTTP::ServerEventArgs& evt, 68 | const ofJson& id, 69 | const std::string& method, 70 | const ofJson& parameters); 71 | 72 | /// \brief Destroy the ErrorResponse. 73 | virtual ~Request(); 74 | 75 | /// \brief Get the request method. 76 | /// \returns the request method. 77 | const std::string& method() const; 78 | OF_DEPRECATED_MSG("Use method() instead.", const std::string& getMethod() const); 79 | 80 | /// \brief Get the request parameters. 81 | /// \returns the request method parameters. 82 | const ofJson& parameters() const; 83 | OF_DEPRECATED_MSG("Use parameters() instead.", const ofJson& getParameters() const); 84 | 85 | /// \brief Query whether this Request is a notification. 86 | /// \returns true iff the id is null. 87 | bool isNotification() const; 88 | 89 | /// \brief Get the JSON Request as a string. 90 | /// \param styled true if the output string should be pretty-print. 91 | /// \returns a raw json string of this Request 92 | std::string toString(bool styled = false) const; 93 | 94 | /// \brief Serialize the Request object to JSON. 95 | /// \param request the Request object to serialize. 96 | /// \returns JSONRPC compatible JSON. 97 | static ofJson toJSON(const Request& request); 98 | 99 | /// \brief Deserialize the JSON to a Request object. 100 | /// \param json JSONRPC compatible JSON to deserialize. 101 | /// \returns deserialized Request. 102 | /// \throws ParseException if the json is not valid. 103 | static Request fromJSON(HTTP::ServerEventArgs& evt, const ofJson& json); 104 | 105 | protected: 106 | /// \brief The method name. 107 | std::string _method; 108 | 109 | /// \brief The method parameters. 110 | ofJson _parameters; 111 | 112 | /// \brief Method tag. 113 | static const std::string METHOD_TAG; 114 | 115 | /// \brief Parameters tag. 116 | static const std::string PARAMS_TAG; 117 | 118 | }; 119 | 120 | 121 | } } // namespace ofx::JSONRPC 122 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/include/ofx/JSONRPC/Response.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include 12 | #include 13 | #include "json.hpp" 14 | #include "ofx/JSONRPC/Error.h" 15 | #include "ofx/JSONRPC/BaseMessage.h" 16 | 17 | 18 | namespace ofx { 19 | namespace JSONRPC { 20 | 21 | 22 | /// \brief A JSONRPC 2.0 Response. 23 | /// 24 | /// A Response has the following format: 25 | /// 26 | /// ~~~{.json} 27 | /// { 28 | /// "jsonrpc": "2.0", 29 | /// "result": 19, 30 | /// "id": 1 31 | /// } 32 | /// ~~~ 33 | /// 34 | /// \sa http://www.jsonrpc.org/specification 35 | class Response: public BaseMessage 36 | { 37 | public: 38 | /// \brief Create a default Error Response. 39 | Response(HTTP::ServerEventArgs& evt); 40 | 41 | /// \brief Create a successful Response. 42 | /// \param id The id of the original remote call. 43 | /// \param result The results of the function call as JSON. 44 | Response(HTTP::ServerEventArgs& evt, 45 | const ofJson& id, 46 | const ofJson& result); 47 | 48 | /// \brief Create an Error Response. 49 | /// \param id The id of the original remote call. 50 | /// \param error The Error response. The Error MUST 51 | /// contain a valid error code. 52 | Response(HTTP::ServerEventArgs& evt, 53 | const ofJson& id, 54 | const Error& error); 55 | 56 | /// \brief Destroy the Response. 57 | virtual ~Response(); 58 | 59 | /// \brief Get the Result JSON if available. 60 | /// \returns result JSON data if available. 61 | /// \note The JSON data will be empty if there is an error. 62 | const ofJson& result() const; 63 | OF_DEPRECATED_MSG("Use result() instead.", const ofJson& getResult() const); 64 | 65 | /// \brief Get the Error if available. 66 | /// 67 | /// The Error code will be NO_ERROR if the call was successful. 68 | /// 69 | /// \returns the Error if available. 70 | const Error& error() const; 71 | OF_DEPRECATED_MSG("Use error() instead.", const Error& getError() const); 72 | 73 | /// \brief Query if the Response is an error response. 74 | /// \returns true iff an error code is present. 75 | bool isErrorResponse() const; 76 | 77 | /// \brief Get the JSON Response as a string. 78 | /// \param styled true if the output string should be pretty-print. 79 | /// \returns a raw json string of this Response 80 | std::string toString(bool styled = false) const; 81 | 82 | /// \brief Serialize the Response object to JSON. 83 | /// \param response the Response object to serialize. 84 | /// \returns JSONRPC compatible JSON. 85 | static ofJson toJSON(const Response& response); 86 | 87 | /// \brief Deserialize the JSON to a Response object. 88 | /// \param json JSONRPC compatible JSON to deserialize. 89 | /// \returns the deserialized Response. 90 | /// \throws ParseException if the JSON is not valid. 91 | static Response fromJSON(HTTP::ServerEventArgs& evt, const ofJson& json); 92 | 93 | protected: 94 | /// \brief The result of the remote call. 95 | ofJson _result; 96 | 97 | /// \brief An Error object. Will be empty if there is no error. 98 | Error _error; 99 | 100 | /// \brief Error tag. 101 | static const std::string ERROR_TAG; 102 | 103 | /// \brief Result tag. 104 | static const std::string RESULT_TAG; 105 | 106 | }; 107 | 108 | 109 | } } // namespace ofx::JSONRPC 110 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/BaseMessage.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/BaseMessage.h" 9 | 10 | 11 | namespace ofx { 12 | namespace JSONRPC { 13 | 14 | 15 | const std::string BaseMessage::PROTOCOL_VERSION_TAG = "jsonrpc"; 16 | const std::string BaseMessage::PROTOCOL_VERSION = "2.0"; 17 | const std::string BaseMessage::ID_TAG = "id"; 18 | 19 | 20 | BaseMessage::BaseMessage(HTTP::ServerEventArgs& evt, 21 | const ofJson& id): 22 | HTTP::ServerEventArgs(evt), 23 | _id(id) 24 | { 25 | } 26 | 27 | 28 | BaseMessage::~BaseMessage() 29 | { 30 | } 31 | 32 | 33 | const ofJson& BaseMessage::id() const 34 | { 35 | return _id; 36 | } 37 | 38 | 39 | ofJson BaseMessage::getId() const 40 | { 41 | return _id; 42 | } 43 | 44 | 45 | bool BaseMessage::hasId() const 46 | { 47 | return !_id.empty(); 48 | } 49 | 50 | 51 | } } // namespace ofx::JSONRPC 52 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/Error.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/Error.h" 9 | #include "ofx/JSONRPC/JSONRPCUtils.h" 10 | 11 | 12 | namespace ofx { 13 | namespace JSONRPC { 14 | 15 | 16 | const std::string Error::ERROR_CODE_TAG = "code"; 17 | const std::string Error::ERROR_MESSAGE_TAG = "message"; 18 | const std::string Error::ERROR_DATA_TAG = "data"; 19 | 20 | 21 | Error::Error(): 22 | _code(Errors::RPC_ERROR_NONE), 23 | _message(Errors::getErrorMessage(_code)), 24 | _data(ofJson()) 25 | { 26 | } 27 | 28 | 29 | Error::Error(int code): 30 | _code(code), 31 | _message(Errors::getErrorMessage(code)), 32 | _data(ofJson()) 33 | { 34 | } 35 | 36 | 37 | Error::Error(int code, const ofJson& data): 38 | _code(code), 39 | _message(Errors::getErrorMessage(_code)), 40 | _data(data) 41 | { 42 | } 43 | 44 | 45 | Error::Error(int code, const std::string& message, const ofJson& data): 46 | _code(code), 47 | _message(message), 48 | _data(data) 49 | { 50 | } 51 | 52 | 53 | Error::~Error() 54 | { 55 | } 56 | 57 | 58 | int Error::code() const 59 | { 60 | return _code; 61 | } 62 | 63 | 64 | int Error::getCode() const 65 | { 66 | return code(); 67 | } 68 | 69 | 70 | const std::string& Error::message() const 71 | { 72 | return _message; 73 | } 74 | 75 | 76 | std::string Error::getMessage() const 77 | { 78 | return message(); 79 | } 80 | 81 | 82 | const ofJson& Error::data() const 83 | { 84 | return _data; 85 | } 86 | 87 | 88 | ofJson Error::getData() const 89 | { 90 | return data(); 91 | } 92 | 93 | 94 | ofJson Error::toJSON(const Error& error) 95 | { 96 | ofJson result; 97 | 98 | result[ERROR_CODE_TAG] = error.code(); 99 | 100 | if (!error.message().empty()) 101 | { 102 | result[ERROR_MESSAGE_TAG] = error.message(); 103 | } 104 | 105 | if (!error.data().is_null()) 106 | { 107 | result[ERROR_DATA_TAG] = error.data(); 108 | } 109 | 110 | return result; 111 | } 112 | 113 | Error Error::fromJSON(const ofJson& json) 114 | { 115 | if (JSONRPCUtils::hasIntegerKey(json, ERROR_CODE_TAG)) 116 | { 117 | int code = json[ERROR_CODE_TAG]; 118 | 119 | if (JSONRPCUtils::hasStringKey(json, ERROR_MESSAGE_TAG)) 120 | { 121 | std::string message = json[ERROR_MESSAGE_TAG]; 122 | 123 | if (JSONRPCUtils::hasKey(json, ERROR_DATA_TAG)) 124 | { 125 | ofJson data = json[ERROR_DATA_TAG]; 126 | return Error(code, message, data); 127 | } 128 | else 129 | { 130 | return Error(code, message); 131 | } 132 | } 133 | else 134 | { 135 | return Error(code); 136 | } 137 | } 138 | else 139 | { 140 | return Error(Errors::RPC_ERROR_PARSE); 141 | } 142 | } 143 | 144 | 145 | } } // namespace ofx::JSONRPC 146 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/Errors.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/Errors.h" 9 | #include 10 | 11 | 12 | namespace ofx { 13 | namespace JSONRPC { 14 | 15 | 16 | const int Errors::RPC_ERROR_NONE = 0; 17 | const int Errors::RPC_ERROR_INVALID_REQUEST = -32600; 18 | const int Errors::RPC_ERROR_METHOD_NOT_FOUND = -32601; 19 | const int Errors::RPC_ERROR_INVALID_PARAMETERS = -32602; 20 | const int Errors::RPC_ERROR_INTERNAL_ERROR = -32603; 21 | const int Errors::RPC_ERROR_PARSE = -32700; 22 | 23 | 24 | std::string Errors::getErrorMessage(int code) 25 | { 26 | switch (code) 27 | { 28 | case Errors::RPC_ERROR_NONE: 29 | return "RPC_ERROR_NONE"; 30 | case Errors::RPC_ERROR_INVALID_REQUEST: 31 | return "RPC_ERROR_INVALID_REQUEST"; 32 | case Errors::RPC_ERROR_METHOD_NOT_FOUND: 33 | return "RPC_ERROR_METHOD_NOT_FOUND"; 34 | case Errors::RPC_ERROR_INVALID_PARAMETERS: 35 | return "RPC_ERROR_INVALID_PARAMETERS"; 36 | case Errors::RPC_ERROR_INTERNAL_ERROR: 37 | return "RPC_ERROR_INTERNAL_ERROR"; 38 | case Errors::RPC_ERROR_PARSE: 39 | return "RPC_ERROR_PARSE"; 40 | default: 41 | { 42 | if (code >= -32099 && code <= -32000) 43 | { 44 | return "undefined server error"; 45 | } 46 | else 47 | { 48 | return "Unknown Error"; 49 | } 50 | } 51 | } 52 | } 53 | 54 | 55 | POCO_IMPLEMENT_EXCEPTION(JSONRPCException, 56 | Poco::Exception, 57 | "RPC_ERROR_INTERNAL_ERROR") 58 | 59 | 60 | POCO_IMPLEMENT_EXCEPTION(InvalidRequestException, 61 | JSONRPCException, 62 | "RPC_ERROR_INVALID_REQUEST") 63 | 64 | POCO_IMPLEMENT_EXCEPTION(MethodNotFoundException, 65 | JSONRPCException, 66 | "RPC_ERROR_METHOD_NOT_FOUND") 67 | 68 | POCO_IMPLEMENT_EXCEPTION(InvalidParametersException, 69 | JSONRPCException, 70 | "RPC_ERROR_INVALID_PARAMETERS") 71 | 72 | POCO_IMPLEMENT_EXCEPTION(InternalErrorException, 73 | JSONRPCException, 74 | "RPC_ERROR_INTERNAL_ERROR") 75 | 76 | POCO_IMPLEMENT_EXCEPTION(ParseException, 77 | JSONRPCException, 78 | "RPC_ERROR_PARSE") 79 | 80 | 81 | } } // namespace ofx::JSONRPC 82 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/JSONRPCUtils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/JSONRPCUtils.h" 9 | 10 | 11 | namespace ofx { 12 | namespace JSONRPC { 13 | 14 | 15 | std::string JSONRPCUtils::toString(const ofJson& json, bool styled) 16 | { 17 | std::string raw; 18 | 19 | if (styled) 20 | { 21 | raw = json.dump(4); 22 | } 23 | else 24 | { 25 | raw = json.dump(); 26 | } 27 | 28 | return raw; 29 | } 30 | 31 | 32 | bool JSONRPCUtils::hasKey(const ofJson& json, const std::string& key) 33 | { 34 | return json.find(key) != json.end(); 35 | } 36 | 37 | 38 | bool JSONRPCUtils::hasKeyOfType(const ofJson& json, 39 | const std::string& key, 40 | ofJson::value_t type) 41 | { 42 | auto i = json.find(key); 43 | 44 | if (i != json.end()) 45 | { 46 | if (i->type() == type) 47 | { 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | return false; 55 | } 56 | 57 | 58 | bool JSONRPCUtils::hasStringKey(const ofJson& json, 59 | const std::string& key) 60 | { 61 | return hasKeyOfType(json, key, ofJson::value_t::string); 62 | } 63 | 64 | 65 | bool JSONRPCUtils::hasIntegerKey(const ofJson& json, 66 | const std::string& key) 67 | { 68 | return hasKeyOfType(json, key, ofJson::value_t::number_integer); 69 | } 70 | 71 | 72 | } } // namespace ofx::JSONRPC 73 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/MethodArgs.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/MethodArgs.h" 9 | 10 | 11 | namespace ofx { 12 | namespace JSONRPC { 13 | 14 | 15 | MethodArgs::MethodArgs(HTTP::ServerEventArgs& evt, 16 | const ofJson& params): 17 | HTTP::ServerEventArgs(evt), 18 | params(params), 19 | result(nullptr), 20 | error(Error()) 21 | { 22 | } 23 | 24 | 25 | MethodArgs::~MethodArgs() 26 | { 27 | } 28 | 29 | 30 | std::string MethodArgs::toString(bool styled) const 31 | { 32 | std::stringstream ss; 33 | 34 | ss << "Params:" << std::endl; 35 | ss << JSONRPCUtils::toString(params, styled) << std::endl; 36 | ss << "Results:" << std::endl; 37 | ss << JSONRPCUtils::toString(result, styled) << std::endl; 38 | ss << "Error:" << std::endl; 39 | ss << JSONRPCUtils::toString(Error::toJSON(error), styled) << std::endl; 40 | 41 | return ss.str(); 42 | } 43 | 44 | 45 | } } // namespace ofx::JSONRPC 46 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/MethodRegistry.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/MethodRegistry.h" 9 | 10 | 11 | namespace ofx { 12 | namespace JSONRPC { 13 | 14 | 15 | MethodRegistry::MethodRegistry() 16 | { 17 | } 18 | 19 | 20 | MethodRegistry::~MethodRegistry() 21 | { 22 | } 23 | 24 | 25 | void MethodRegistry::unregisterMethod(const std::string& method) 26 | { 27 | std::unique_lock lock(_mutex); 28 | 29 | MethodMapIter methodIter = _methodMap.find(method); 30 | 31 | if (methodIter != _methodMap.end()) 32 | { 33 | _methodMap.erase(methodIter); 34 | return; 35 | } 36 | 37 | NoArgMethodMapIter noArgMethodIter = _noArgMethodMap.find(method); 38 | 39 | if (noArgMethodIter != _noArgMethodMap.end()) 40 | { 41 | _noArgMethodMap.erase(noArgMethodIter); 42 | return; 43 | } 44 | } 45 | 46 | 47 | Response MethodRegistry::processCall(const void* pSender, Request& request) 48 | { 49 | try 50 | { 51 | std::unique_lock lock(_mutex); 52 | 53 | const std::string& method = request.method(); 54 | 55 | NoArgMethodMapIter noArgMethodIter = _noArgMethodMap.find(method); 56 | 57 | MethodMapIter methodIter = _methodMap.find(method); 58 | 59 | if (methodIter != _methodMap.end()) 60 | { 61 | MethodArgs args(request, request.parameters()); 62 | 63 | // Argument result is filled in the event notification callback. 64 | ofNotifyEvent((*methodIter).second->event, args, pSender); 65 | 66 | // If an error is present, then ignore any args.results 67 | // and return the error response. 68 | if (Errors::RPC_ERROR_NONE == args.error.code()) 69 | { 70 | return Response(request, 71 | request.id(), 72 | args.result); 73 | } 74 | else 75 | { 76 | // Return the error. 77 | return Response(request, 78 | request.id(), 79 | args.error); 80 | } 81 | } 82 | else if (noArgMethodIter != _noArgMethodMap.end()) 83 | { 84 | if (request.parameters().is_null()) 85 | { 86 | ofNotifyEvent((*noArgMethodIter).second->event, pSender); 87 | 88 | return Response(request, request.id(), nullptr); 89 | } 90 | else 91 | { 92 | return Response(request, 93 | request.id(), 94 | Error(Errors::RPC_ERROR_INVALID_REQUEST, 95 | "This method does not support parameters.", 96 | Request::toJSON(request))); 97 | } 98 | } 99 | else 100 | { 101 | return Response(request, 102 | request.id(), 103 | Error(Errors::RPC_ERROR_METHOD_NOT_FOUND, 104 | Request::toJSON(request))); 105 | } 106 | } 107 | catch (const JSONRPCException& exc) 108 | { 109 | return Response(request, 110 | request.id(), 111 | Error(exc.code(), 112 | exc.message())); 113 | } 114 | catch (const Poco::InvalidArgumentException& exc) 115 | { 116 | return Response(request, 117 | request.id(), 118 | Error(Errors::RPC_ERROR_INVALID_PARAMETERS, 119 | Request::toJSON(request))); 120 | } 121 | catch (const Poco::Exception& exc) 122 | { 123 | return Response(request, 124 | request.id(), 125 | Error(Errors::RPC_ERROR_INTERNAL_ERROR, 126 | exc.displayText(), 127 | Request::toJSON(request))); 128 | } 129 | catch (const std::exception& exc) 130 | { 131 | return Response(request, 132 | request.id(), 133 | Error(Errors::RPC_ERROR_INTERNAL_ERROR, 134 | exc.what(), 135 | Request::toJSON(request))); 136 | } 137 | catch ( ... ) 138 | { 139 | return Response(request, 140 | request.id(), 141 | Error(Errors::RPC_ERROR_INTERNAL_ERROR, 142 | "Unknown Exception", 143 | Request::toJSON(request))); 144 | } 145 | } 146 | 147 | 148 | void MethodRegistry::processNotification(const void* pSender, Request& request) 149 | { 150 | processCall(pSender, request); // return nothing 151 | } 152 | 153 | 154 | bool MethodRegistry::hasMethod(const std::string& method) const 155 | { 156 | std::unique_lock lock(_mutex); 157 | return _methodMap.find(method) != _methodMap.end(); 158 | } 159 | 160 | 161 | MethodRegistry::MethodDescriptionMap MethodRegistry::methods() const 162 | { 163 | std::unique_lock lock(_mutex); 164 | MethodRegistry::MethodDescriptionMap methods; 165 | 166 | for (const auto& method: _methodMap) 167 | { 168 | methods[method.first] = method.second->description(); 169 | } 170 | 171 | return methods; 172 | } 173 | 174 | 175 | MethodRegistry::MethodDescriptionMap MethodRegistry::getMethods() const 176 | { 177 | return methods(); 178 | } 179 | 180 | 181 | } } // namespace ofx::JSONRPC 182 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/Request.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/Request.h" 9 | #include "ofx/JSONRPC/JSONRPCUtils.h" 10 | 11 | 12 | namespace ofx { 13 | namespace JSONRPC { 14 | 15 | 16 | const std::string Request::METHOD_TAG = "method"; 17 | const std::string Request::PARAMS_TAG = "params"; 18 | 19 | 20 | Request::Request(HTTP::ServerEventArgs& evt, const std::string& method): 21 | BaseMessage(evt, nullptr), 22 | _method(method), 23 | _parameters(nullptr) 24 | { 25 | } 26 | 27 | 28 | Request::Request(HTTP::ServerEventArgs& evt, 29 | const std::string& method, 30 | const ofJson& parameters): 31 | BaseMessage(evt, nullptr), 32 | _method(method), 33 | _parameters(parameters) 34 | { 35 | } 36 | 37 | 38 | Request::Request(HTTP::ServerEventArgs& evt, 39 | const ofJson& id, 40 | const std::string& method): 41 | BaseMessage(evt, id), 42 | _method(method), 43 | _parameters(nullptr) 44 | { 45 | } 46 | 47 | 48 | Request::Request(HTTP::ServerEventArgs& evt, 49 | const ofJson& id, 50 | const std::string& method, 51 | const ofJson& parameters): 52 | 53 | BaseMessage(evt, id), 54 | _method(method), 55 | _parameters(parameters) 56 | { 57 | } 58 | 59 | 60 | Request::~Request() 61 | { 62 | } 63 | 64 | 65 | const std::string& Request::method() const 66 | { 67 | return _method; 68 | } 69 | 70 | 71 | const std::string& Request::getMethod() const 72 | { 73 | return method(); 74 | } 75 | 76 | 77 | const ofJson& Request::parameters() const 78 | { 79 | return _parameters; 80 | } 81 | 82 | 83 | const ofJson& Request::getParameters() const 84 | { 85 | return parameters(); 86 | } 87 | 88 | 89 | bool Request::isNotification() const 90 | { 91 | return !hasId(); 92 | } 93 | 94 | 95 | std::string Request::toString(bool styled) const 96 | { 97 | return JSONRPCUtils::toString(toJSON(*this), styled); 98 | } 99 | 100 | 101 | ofJson Request::toJSON(const Request& request) 102 | { 103 | ofJson result; 104 | 105 | result[PROTOCOL_VERSION_TAG] = PROTOCOL_VERSION; 106 | 107 | result[ID_TAG] = request.id(); 108 | result[METHOD_TAG] = request.method(); 109 | 110 | if (!request.parameters().is_null()) 111 | { 112 | result[PARAMS_TAG] = request.parameters(); 113 | } 114 | 115 | return result; 116 | } 117 | 118 | 119 | Request Request::fromJSON(HTTP::ServerEventArgs& evt, 120 | const ofJson& json) 121 | { 122 | if (JSONRPCUtils::hasStringKey(json, PROTOCOL_VERSION_TAG) && 123 | json[PROTOCOL_VERSION_TAG] == PROTOCOL_VERSION) 124 | { 125 | if (JSONRPCUtils::hasStringKey(json, METHOD_TAG)) 126 | { 127 | std::string method = json[METHOD_TAG]; 128 | 129 | if (JSONRPCUtils::hasKey(json, ID_TAG)) 130 | { 131 | ofJson id = json[ID_TAG]; 132 | 133 | if (JSONRPCUtils::hasKey(json, PARAMS_TAG)) 134 | { 135 | ofJson params = json[PARAMS_TAG]; 136 | return Request(evt, id, method, params); 137 | } 138 | else 139 | { 140 | return Request(evt, id, method); 141 | } 142 | } 143 | else 144 | { 145 | if (JSONRPCUtils::hasKey(json, PARAMS_TAG)) 146 | { 147 | ofJson params = json[PARAMS_TAG]; 148 | return Request(evt, method, params); 149 | } 150 | else 151 | { 152 | return Request(evt, method); 153 | } 154 | } 155 | } 156 | else 157 | { 158 | throw ParseException("No method."); 159 | } 160 | } 161 | else 162 | { 163 | throw ParseException("No version string."); 164 | } 165 | } 166 | 167 | 168 | } } // namespace ofx::JSONRPC 169 | -------------------------------------------------------------------------------- /libs/ofxJSONRPC/src/Response.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #include "ofx/JSONRPC/Response.h" 9 | #include "ofx/JSONRPC/JSONRPCUtils.h" 10 | 11 | 12 | namespace ofx { 13 | namespace JSONRPC { 14 | 15 | 16 | const std::string Response::ERROR_TAG = "error"; 17 | const std::string Response::RESULT_TAG = "result"; 18 | 19 | 20 | Response::Response(HTTP::ServerEventArgs& evt): 21 | BaseMessage(evt, ofJson(nullptr)), 22 | _result(ofJson(nullptr)), 23 | _error(Error(Errors::RPC_ERROR_INTERNAL_ERROR)) 24 | { 25 | } 26 | 27 | 28 | Response::Response(HTTP::ServerEventArgs& evt, 29 | const ofJson& id, 30 | const ofJson& result): 31 | BaseMessage(evt, id), 32 | _result(result), 33 | _error(Error()) 34 | { 35 | } 36 | 37 | 38 | Response::Response(HTTP::ServerEventArgs& evt, 39 | const ofJson& id, 40 | const Error& error): 41 | BaseMessage(evt, id), 42 | _result(ofJson()), 43 | _error(error) 44 | { 45 | } 46 | 47 | 48 | Response::~Response() 49 | { 50 | } 51 | 52 | 53 | const ofJson& Response::result() const 54 | { 55 | return _result; 56 | } 57 | 58 | 59 | const ofJson& Response::getResult() const 60 | { 61 | return result(); 62 | } 63 | 64 | const Error& Response::error() const 65 | { 66 | return _error; 67 | } 68 | 69 | 70 | const Error& Response::getError() const 71 | { 72 | return error(); 73 | } 74 | 75 | 76 | bool Response::isErrorResponse() const 77 | { 78 | return Errors::RPC_ERROR_NONE != error().code(); 79 | } 80 | 81 | 82 | std::string Response::toString(bool styled) const 83 | { 84 | return JSONRPCUtils::toString(toJSON(*this), styled); 85 | } 86 | 87 | 88 | ofJson Response::toJSON(const Response& response) 89 | { 90 | ofJson result; 91 | 92 | result[PROTOCOL_VERSION_TAG] = PROTOCOL_VERSION; 93 | 94 | result["id"] = response.id(); 95 | 96 | if (response.isErrorResponse()) 97 | { 98 | result["error"] = Error::toJSON(response.error()); 99 | } 100 | else 101 | { 102 | result["result"] = response.result(); 103 | } 104 | 105 | return result; 106 | } 107 | 108 | 109 | Response Response::fromJSON(HTTP::ServerEventArgs& evt, const ofJson& json) 110 | { 111 | if (JSONRPCUtils::hasStringKey(json, PROTOCOL_VERSION_TAG) && 112 | json[PROTOCOL_VERSION_TAG].get() == PROTOCOL_VERSION) 113 | { 114 | if (JSONRPCUtils::hasKey(json, ID_TAG)) 115 | { 116 | ofJson id = json[ID_TAG]; 117 | 118 | if (JSONRPCUtils::hasKey(json, RESULT_TAG)) 119 | { 120 | ofJson result = json[RESULT_TAG]; 121 | return Response(evt, id, result); 122 | } 123 | else if(JSONRPCUtils::hasKey(json, ERROR_TAG)) 124 | { 125 | ofJson error = json[ERROR_TAG]; 126 | return Response(evt, id, Error::fromJSON(error)); 127 | } 128 | else 129 | { 130 | throw ParseException("No result OR error."); 131 | } 132 | } 133 | else 134 | { 135 | throw ParseException("No ID."); 136 | } 137 | } 138 | else 139 | { 140 | throw ParseException("No version string."); 141 | } 142 | } 143 | 144 | 145 | } } // namespace ofx::JSONRPC 146 | -------------------------------------------------------------------------------- /ofxaddons_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bakercp/ofxJSONRPC/c4512f0e4bae9f6e4b57a48af1b4af6e1302d545/ofxaddons_thumbnail.png -------------------------------------------------------------------------------- /src/ofxJSONRPC.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Christopher Baker 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // 6 | 7 | 8 | #pragma once 9 | 10 | 11 | #include "json.hpp" 12 | #include "ofxHTTP.h" 13 | #include "ofx/JSONRPC/BaseMessage.h" 14 | #include "ofx/JSONRPC/Error.h" 15 | #include "ofx/JSONRPC/Errors.h" 16 | #include "ofx/JSONRPC/MethodArgs.h" 17 | #include "ofx/JSONRPC/MethodRegistry.h" 18 | #include "ofx/JSONRPC/Request.h" 19 | #include "ofx/JSONRPC/Response.h" 20 | #include "ofx/HTTP/JSONRPCServer.h" 21 | 22 | namespace ofxJSONRPC = ofx::JSONRPC; 23 | --------------------------------------------------------------------------------