├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── lib ├── Newtonsoft.Json.dll ├── Raspberry.IO.GeneralPurpose.dll ├── Raspberry.IO.Interop.dll ├── Raspberry.IO.dll ├── Raspberry.System.dll ├── log4net.dll └── nunit.framework.dll └── src ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── Raspkate.Modules.Default ├── DefaultModule.cs ├── DefaultRaspkateController.cs ├── Properties │ └── AssemblyInfo.cs ├── Raspkate.Modules.Default.csproj ├── Raspkate.snk ├── settings.json └── web │ ├── css │ ├── bootstrap-theme.min.css │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── js │ ├── bootstrap.min.js │ └── jquery-1.11.3.min.js │ └── raspkate.html ├── Raspkate.Modules.RaspberryPi ├── Module.cs ├── PinDescription.cs ├── PinType.cs ├── Properties │ └── AssemblyInfo.cs ├── RaspberryController.cs ├── Raspkate.Modules.RaspberryPi.csproj ├── Raspkate.snk └── web │ ├── css │ ├── bootstrap-theme.min.css │ ├── bootstrap.min.css │ └── site.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── js │ ├── bootstrap.min.js │ └── jquery-1.11.3.min.js │ └── raspberrypi.html ├── Raspkate.Service ├── App.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Raspkate.Service.csproj └── Raspkate.snk ├── Raspkate.Tests ├── Properties │ └── AssemblyInfo.cs ├── Raspkate.Tests.csproj ├── Raspkate.snk └── RoutingTests.cs ├── Raspkate.sln ├── Raspkate ├── Config │ ├── ConfigurationException.cs │ ├── RaspkateConfig.csd │ ├── RaspkateConfig.csd.config │ ├── RaspkateConfig.csd.cs │ ├── RaspkateConfig.csd.diagram │ └── RaspkateConfig.csd.xsd ├── Controllers │ ├── ControllerException.cs │ ├── FromBodyAttribute.cs │ ├── HttpGetAttribute.cs │ ├── HttpMethodAttribute.cs │ ├── HttpPostAttribute.cs │ ├── RaspkateController.cs │ ├── RouteAttribute.cs │ ├── RoutePrefixAttribute.cs │ ├── Routing │ │ ├── LiteralRouteItem.cs │ │ ├── ParameterRouteItem.cs │ │ ├── Route.cs │ │ ├── RouteItem.cs │ │ ├── RouteItemAttribute.cs │ │ ├── RouteParseException.cs │ │ ├── RouteParser.cs │ │ └── RouteValueCollection.cs │ └── SynchronizedAttribute.cs ├── HandlerProcessResult.cs ├── Handlers │ ├── ControllerHandler.cs │ ├── ControllerRegistration.cs │ └── FileHandler.cs ├── IRaspkateHandler.cs ├── IRaspkateModule.cs ├── IRaspkateServer.cs ├── Modules │ ├── ModuleContext.cs │ └── RaspkateModule.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Raspkate.csproj ├── Raspkate.snk ├── RaspkateException.cs ├── RaspkateHandler.cs ├── RaspkateServer.cs └── Utils.cs ├── build.bat └── build.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | 238 | #Archives 239 | *.tar 240 | *.tar.bz2 241 | *.tar.gz 242 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspkate 2 | Raspkate is a small, lightweight web server that can both hosts static files and provides RESTful services. Raspkate is also open for extension, which means you can extend it to meet your business needs on top of the HTTP request and response contexts without having to know much detail about the underlying implementation. 3 | 4 | [![Build Status](http://daxnet.me:8080/jenkins/buildStatus/icon?job=Raspkate)](http://daxnet.me:8080/jenkins/job/Raspkate) 5 | 6 | User Scenarios 7 | -- 8 | You can use Raspkate as: 9 | 10 | - A small HTTP server embedded in your application to provide powerful HTML and Javascript hosting 11 | - A standalone system service to serve your HTTP requests 12 | - A RESTful service to receive HTTP requests and provide RESTful APIs 13 | - A lightweight web server running on a small device (like Raspberry Pi) to provide professional HTML user interfaces for manipulating the device 14 | 15 | Source Code 16 | -- 17 | Raspkate was developed with Microsoft Visual Studio 2013 in C# language, with .NET Framework 4.5.2. It can also be compiled and run under Linux system on top of the Mono framework. This project is licensed under [GPL v2.0](http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html), as one of its dependencies used for Raspberry Pi compatibility, was released under this license. 18 | 19 | ### Prerequisites 20 | For development in Windows: 21 | 22 | - Windows 7, 8, 8.1, 10 23 | - Visual Studio 2013/2015 with .NET Framework 4.5.2 24 | 25 | For run in Linux: 26 | 27 | - Ubuntu server 14.04.4 LTS was qualified 28 | - [Raspbian JESSIE](https://www.raspberrypi.org/downloads/raspbian/) was qualified 29 | - Mono 4.2.2 or above was qualified 30 | 31 | ### How to Use the Code 32 | Before compile and run, you should firstly either download the source code as a zip archive or clone the source repository to your local simply by the following git command: 33 | 34 | `git clone https://github.com/daxnet/raspkate.git` 35 | 36 | - For development in Windows, you can open the `raspkate.sln` file directly with Microsoft Visual Studio 2013 or Microsoft Visual Studio 2015 and build the entire solution. 37 | 38 | - For compilation in Windows, you can run the `build.bat` with `Debug` or `Release` as its parameter to compile the source code. `msbuild` in both 12.0 and 14.0 should be supported. 39 | 40 | - For compilation in Linux, you need firstly install the Mono framework. For more information about how to install Mono, please click [here](http://www.mono-project.com/docs/compiling-mono/linux/) for the steps. After you have successfully installed Mono framework, run the `build.sh` with either `Debug` or `Release` as its parameter to compile the source code. 41 | 42 | - For running in both Windows and Linux, after the successful compilation in either platform, go into the `bin` folder which is a sub folder of `src`, and find the executable file named `RaspkateService.exe` under the output folder of corresponding configuration (e.g. `Debug` or `Release`), execute it directly, you will see a console output like following: 43 | 44 | ![Service Started](https://raw.githubusercontent.com/wiki/daxnet/raspkate/img/ServiceStarted.png) 45 | 46 | - After successfully running the server, you can access `http://127.0.0.1:9023` in your web browser to check your server information, like below: 47 | 48 | ![Server Information](https://raw.githubusercontent.com/wiki/daxnet/raspkate/img/Congrats.png) 49 | 50 | > Important Note: If you are going to load `Raspkate.RaspberryPi` module during the server startup, in order that to be able to access the functionality specific to Raspberry Pi device, you should run Raspkate service under Raspberry Pi by using the command `sudo ./RaspkateService.exe` with the root priviledge granted. 51 | 52 | Documentation 53 | -- 54 | - [Architecture Overview](https://github.com/daxnet/raspkate/wiki/Architecture-Overview) 55 | 56 | -------------------------------------------------------------------------------- /lib/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /lib/Raspberry.IO.GeneralPurpose.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/Raspberry.IO.GeneralPurpose.dll -------------------------------------------------------------------------------- /lib/Raspberry.IO.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/Raspberry.IO.Interop.dll -------------------------------------------------------------------------------- /lib/Raspberry.IO.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/Raspberry.IO.dll -------------------------------------------------------------------------------- /lib/Raspberry.System.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/Raspberry.System.dll -------------------------------------------------------------------------------- /lib/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/log4net.dll -------------------------------------------------------------------------------- /lib/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/lib/nunit.framework.dll -------------------------------------------------------------------------------- /src/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/.nuget/NuGet.exe -------------------------------------------------------------------------------- /src/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/DefaultModule.cs: -------------------------------------------------------------------------------- 1 | using Raspkate.Config; 2 | using Raspkate.Handlers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Raspkate.Modules.Default 11 | { 12 | internal sealed class DefaultModule : RaspkateModule 13 | { 14 | public DefaultModule(ModuleContext context) 15 | : base(context) 16 | { } 17 | 18 | protected override IEnumerable CreateHandlers() 19 | { 20 | var defaultPages = this.Context.ReadSetting("FileHandler.DefaultPages"); 21 | if (string.IsNullOrEmpty(defaultPages)) 22 | { 23 | throw new ConfigurationException("No DefaultPages specified."); 24 | } 25 | 26 | var fileHandlerBasePath = this.Context.ReadSetting("FileHandler.BasePath"); 27 | if (string.IsNullOrEmpty(fileHandlerBasePath)) 28 | { 29 | throw new ConfigurationException("No BasePath specified."); 30 | } 31 | 32 | var fileHandlerIsRelativePath = this.Context.ReadSetting("FileHandler.IsRelativePath"); 33 | var isRelativePath = false; 34 | bool.TryParse(fileHandlerIsRelativePath, out isRelativePath); 35 | 36 | var basePath = fileHandlerBasePath; 37 | if (isRelativePath) 38 | { 39 | basePath = Path.Combine(Context.ModuleFolder, basePath); 40 | } 41 | 42 | yield return new FileHandler("Raspkate.Modules.DefaultModule.FileHandler", defaultPages, basePath); 43 | yield return new ControllerHandler("Raspkate.Modules.DefaultModule.ControllerHandler", new[] { typeof(DefaultRaspkateController) }); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/DefaultRaspkateController.cs: -------------------------------------------------------------------------------- 1 | using Raspkate.Controllers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Modules.Default 9 | { 10 | [RoutePrefix("api")] 11 | [Synchronized] 12 | public class DefaultRaspkateController : RaspkateController 13 | { 14 | public DefaultRaspkateController() 15 | { 16 | } 17 | 18 | [HttpGet] 19 | [Route("server/info")] 20 | public dynamic GetServerInfo() 21 | { 22 | return new 23 | { 24 | Environment.MachineName, 25 | Environment.Is64BitOperatingSystem, 26 | OSVersion = Environment.OSVersion.VersionString, 27 | OSPlatform = Enum.GetName(typeof(PlatformID), Environment.OSVersion.Platform), 28 | OSServicePack = Environment.OSVersion.ServicePack, 29 | Environment.ProcessorCount, 30 | Environment.SystemDirectory, 31 | Environment.SystemPageSize, 32 | FrameworkVersion = Environment.Version.ToString() 33 | }; 34 | } 35 | 36 | //[HttpPost] 37 | //[Route("setPin/{pin}/{value}")] 38 | //public void SetPinValue(int pin, bool value) 39 | //{ 40 | // if (isRaspberryPi) 41 | // { 42 | // var p = ((ConnectorPin)pin).ToProcessor(); 43 | // var driver = GpioConnectionSettings.DefaultDriver; 44 | // driver.Allocate(p, PinDirection.Output); 45 | // driver.Write(p, value); 46 | // } 47 | //} 48 | 49 | //[HttpGet] 50 | //[Route("getPin/{pin}")] 51 | //public bool GetPinValue(int pin) 52 | //{ 53 | // if (isRaspberryPi) 54 | // { 55 | // var p = ((ConnectorPin)pin).ToProcessor(); 56 | // var driver = GpioConnectionSettings.DefaultDriver; 57 | // return driver.Read(p); 58 | // } 59 | // return false; 60 | //} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Raspkate.Modules")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Raspkate.Modules")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("59273cf5-6f6f-4cb4-a020-9f839e8be8b8")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/Raspkate.Modules.Default.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5} 8 | Library 9 | Properties 10 | Raspkate.Modules.Default 11 | Raspkate.Modules.Default 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | ..\..\bin\modules\default\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | ..\..\bin\modules\default\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | 35 | 36 | Raspkate.snk 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {38bb78ef-cfa0-457a-b216-5b3aff7c5520} 55 | Raspkate 56 | False 57 | 58 | 59 | 60 | 61 | 62 | Always 63 | 64 | 65 | Always 66 | 67 | 68 | Always 69 | 70 | 71 | Always 72 | 73 | 74 | Always 75 | 76 | 77 | 78 | 79 | Always 80 | 81 | 82 | Always 83 | 84 | 85 | Always 86 | 87 | 88 | Always 89 | 90 | 91 | Always 92 | 93 | 94 | Always 95 | 96 | 97 | 98 | 105 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/Raspkate.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.Default/Raspkate.snk -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": [ 3 | { 4 | "key": "FileHandler.DefaultPages", 5 | "value": "raspkate.html;index.htm;index.html" 6 | }, 7 | { 8 | "key": "FileHandler.BasePath", 9 | "value": "web" 10 | }, 11 | { 12 | "key": "FileHandler.IsRelativePath", 13 | "value": "true" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.Default/web/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/Raspkate.Modules.Default/web/raspkate.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Raspkate Service Home Page 7 | 8 | 9 | 10 | 25 | 26 | 27 | 34 |
35 |
36 |

Congratulations!

37 |

You have successfully setup the Raspkate service on your device.

38 |

39 | Learn More... 40 |

41 |
42 |
43 |
44 |

45 | Server Information 46 |

47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
NameValue
57 |
58 |
59 |
60 |
61 |

Copyright © 2016 daxnet.me.

62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/Module.cs: -------------------------------------------------------------------------------- 1 | using Raspkate.Handlers; 2 | using Raspkate.Modules; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Raspkate.Modules.RaspberryPi 12 | { 13 | internal sealed class Module : RaspkateModule 14 | { 15 | public Module(ModuleContext context) 16 | : base(context) 17 | { 18 | 19 | } 20 | 21 | protected override IEnumerable CreateHandlers() 22 | { 23 | yield return new FileHandler("Raspkate.RaspberryPi.Module.FileHandler", "index.htm;index.html", Path.Combine(Context.ModuleFolder, "web")); 24 | yield return new ControllerHandler("Raspkate.RaspberryPi.Module.ControllerHandler", new[] { typeof(RaspberryController) }); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/PinDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Modules.RaspberryPi 8 | { 9 | internal class PinDescription 10 | { 11 | public string Name { get; private set; } 12 | 13 | public PinType Type { get; private set; } 14 | 15 | public int Value { get; set; } 16 | 17 | public PinDescription(string name, PinType type) 18 | { 19 | this.Name = name; 20 | this.Type = type; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/PinType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Modules.RaspberryPi 8 | { 9 | /// 10 | /// Represents the types of the pin. 11 | /// 12 | internal enum PinType 13 | { 14 | Power, 15 | Ground, 16 | Gpio, 17 | I2C, 18 | SPI, 19 | UART, 20 | ID_EEPROM 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Raspkate; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Raspkate.RaspberryPi")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Raspkate.RaspberryPi")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("4d789a69-2ed8-4f44-bae5-0de7cc780885")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | 39 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/RaspberryController.cs: -------------------------------------------------------------------------------- 1 | using Raspberry.IO.GeneralPurpose; 2 | using Raspkate.Controllers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Raspkate.Modules.RaspberryPi 11 | { 12 | /// 13 | /// 14 | /// 15 | [RoutePrefix("raspberry")] 16 | [Synchronized] 17 | internal class RaspberryController : RaspkateController 18 | { 19 | private static readonly bool IsRaspberryPi = Raspberry.Board.Current.IsRaspberryPi; 20 | private static readonly PinDescription[] PinDescriptions = new[] { 21 | new PinDescription("3.3v", PinType.Power), new PinDescription("5v", PinType.Power), 22 | new PinDescription("I2C1_SDA", PinType.I2C), new PinDescription("5v", PinType.Power), 23 | new PinDescription("I2C1_SCL", PinType.I2C), new PinDescription("GND", PinType.Ground), 24 | new PinDescription("GPIO_4", PinType.Gpio), new PinDescription("UART_TXD", PinType.UART), 25 | new PinDescription("GND", PinType.Ground), new PinDescription("UART_RXD", PinType.UART), 26 | new PinDescription("GPIO_17", PinType.Gpio), new PinDescription("GPIO_18", PinType.Gpio), 27 | new PinDescription("GPIO_27", PinType.Gpio), new PinDescription("GND", PinType.Ground), 28 | new PinDescription("GPIO_22", PinType.Gpio), new PinDescription("GPIO_23", PinType.Gpio), 29 | new PinDescription("3.3v", PinType.Power), new PinDescription("GPIO_24", PinType.Gpio), 30 | new PinDescription("SPI_MOSI", PinType.SPI), new PinDescription("GND", PinType.Ground), 31 | new PinDescription("SPI_MISO", PinType.SPI), new PinDescription("GPIO_25", PinType.Gpio), 32 | new PinDescription("SPI_SCLK", PinType.SPI), new PinDescription("SPI_CE0", PinType.SPI), 33 | new PinDescription("GND", PinType.Ground), new PinDescription("SPI_CE1", PinType.SPI), 34 | new PinDescription("ID_SD", PinType.ID_EEPROM), new PinDescription("ID_SC", PinType.ID_EEPROM), 35 | new PinDescription("GPIO_5", PinType.Gpio), new PinDescription("GND", PinType.Ground), 36 | new PinDescription("GPIO_6", PinType.Gpio), new PinDescription("GPIO_12", PinType.Gpio), 37 | new PinDescription("GPIO_13", PinType.Gpio), new PinDescription("GND", PinType.Ground), 38 | new PinDescription("GPIO_19", PinType.Gpio), new PinDescription("GPIO_16", PinType.Gpio), 39 | new PinDescription("GPIO_26", PinType.Gpio), new PinDescription("GPIO_20", PinType.Gpio), 40 | new PinDescription("GND", PinType.Ground), new PinDescription("GPIO_21", PinType.Gpio) 41 | }; 42 | private static readonly IGpioConnectionDriver Driver = GpioConnectionSettings.DefaultDriver; 43 | 44 | /// 45 | /// Gets the Raspberry Pi board information. 46 | /// 47 | /// 48 | [HttpGet] 49 | [Route("board")] 50 | public dynamic GetBoardInformation() 51 | { 52 | return new 53 | { 54 | IsRaspberryPi = IsRaspberryPi, 55 | Raspberry.Board.Current.IsOverclocked, 56 | Firmware = IsRaspberryPi ? Raspberry.Board.Current.Firmware.ToString() : "N/A", 57 | Model = IsRaspberryPi ? Enum.GetName(typeof(Raspberry.Model), Raspberry.Board.Current.Model) : "N/A", 58 | Processor = IsRaspberryPi ? Raspberry.Board.Current.ProcessorName : "N/A", 59 | SerialNumber = IsRaspberryPi ? Raspberry.Board.Current.SerialNumber : "N/A" 60 | }; 61 | } 62 | 63 | [HttpGet] 64 | [Route("pins")] 65 | public dynamic GetPinsStatus() 66 | { 67 | if (IsRaspberryPi) 68 | { 69 | var model = Raspberry.Board.Current.Model; 70 | var totalPins = 26; 71 | if (model == Raspberry.Model.APlus || 72 | model == Raspberry.Model.BPlus || 73 | model == Raspberry.Model.B2) 74 | { 75 | totalPins = 40; 76 | } 77 | var pins = new List(); 78 | var pinNames = Enum.GetNames(typeof(ConnectorPin)); 79 | for (var i = 0; i < totalPins; i++) 80 | { 81 | var pinDescription = PinDescriptions[i]; 82 | pinDescription.Value = 0; 83 | var pinName = string.Format("P1Pin{0:D2}", i + 1); 84 | if (pinNames.Contains(pinName)) 85 | { 86 | ConnectorPin connectorPin; 87 | if (Enum.TryParse(pinName, out connectorPin)) 88 | { 89 | var processorPin = connectorPin.ToProcessor(); 90 | pinDescription.Value = Driver.Read(processorPin) ? 1 : 0; 91 | } 92 | } 93 | pins.Add(pinDescription); 94 | } 95 | 96 | return new 97 | { 98 | Model = Enum.GetName(typeof(Raspberry.Model), model), 99 | Pins = pins 100 | }; 101 | } 102 | return Error("The current device is not a Raspberry Pi...234234."); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/Raspkate.Modules.RaspberryPi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7B1B80ED-D594-4908-8322-C3E76A05AF28} 8 | Library 9 | Properties 10 | Raspkate.Modules.RaspberryPi 11 | Raspkate.Modules.RaspberryPi 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | ..\..\bin\modules\raspberrypi\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | ..\..\bin\modules\raspberrypi\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | 35 | 36 | Raspkate.snk 37 | 38 | 39 | 40 | ..\..\lib\Raspberry.IO.dll 41 | 42 | 43 | ..\..\lib\Raspberry.IO.GeneralPurpose.dll 44 | 45 | 46 | ..\..\lib\Raspberry.IO.Interop.dll 47 | 48 | 49 | ..\..\lib\Raspberry.System.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {38bb78ef-cfa0-457a-b216-5b3aff7c5520} 69 | Raspkate 70 | False 71 | 72 | 73 | 74 | 75 | 76 | Always 77 | 78 | 79 | Always 80 | 81 | 82 | Always 83 | 84 | 85 | Always 86 | 87 | 88 | 89 | 90 | Always 91 | 92 | 93 | Always 94 | 95 | 96 | Always 97 | 98 | 99 | Always 100 | 101 | 102 | Always 103 | 104 | 105 | Always 106 | 107 | 108 | Always 109 | 110 | 111 | 112 | 119 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/Raspkate.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.RaspberryPi/Raspkate.snk -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/css/site.css: -------------------------------------------------------------------------------- 1 | .red { 2 | color: red; 3 | } 4 | 5 | .black { 6 | color: black; 7 | } 8 | 9 | .cyan { 10 | color: cyan; 11 | } 12 | 13 | .orange { 14 | color: orange; 15 | } 16 | 17 | .gray { 18 | color: gray; 19 | } 20 | 21 | .green { 22 | color: green; 23 | } 24 | 25 | .deeppink { 26 | color: deeppink; 27 | } 28 | -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Modules.RaspberryPi/web/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/Raspkate.Modules.RaspberryPi/web/raspberrypi.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | Raspkate Service Raspberry Pi Information Page 12 | 13 | 14 | 15 | 16 | 70 | 71 | 72 | 73 | 74 | 81 |
82 |
83 |

My Raspberry Pi

84 | 85 |
86 |
87 |
88 |
89 |
90 |

91 | Board Information 92 |

93 |
94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
NAMEVALUE
104 |
105 |

106 | This device is not a Raspberry Pi. 107 |

108 |
109 |
110 |

111 | GPIO Pin Details 112 |

113 |
114 |
115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
VALUETYPENAMEIDIDNAMETYPEVALUE
130 |

131 | This device is not a Raspberry Pi. 132 |

133 |
134 |
135 |
136 |
137 |
138 |
139 |

Copyright © 2016 daxnet.me.

140 |
141 | 142 | -------------------------------------------------------------------------------- /src/Raspkate.Service/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Raspkate.Service/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Raspkate.Handlers; 4 | using Raspkate.Config; 5 | using System.Configuration; 6 | 7 | namespace Raspkate.Service 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | RaspkateServer server = new RaspkateServer(RaspkateConfiguration.Instance); 14 | server.Start(); 15 | Console.ReadLine(); 16 | server.Stop(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Raspkate.Service/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Raspkate.ConsoleApp")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Raspkate.ConsoleApp")] 13 | [assembly: AssemblyCopyright("Copyright © 2016 by daxnet.")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4d33d21e-399e-4116-8e45-4b5f8cd0a78c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Raspkate.Service/Raspkate.Service.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1C2E4FD6-39B4-4762-B32C-E3079856A227} 8 | Exe 9 | Properties 10 | Raspkate.Service 11 | RaspkateService 12 | v4.5.2 13 | 512 14 | true 15 | ..\ 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | ..\..\bin\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | ..\..\bin\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | true 39 | 40 | 41 | Raspkate.snk 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Designer 60 | 61 | 62 | 63 | 64 | 65 | {38bb78ef-cfa0-457a-b216-5b3aff7c5520} 66 | Raspkate 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /src/Raspkate.Service/Raspkate.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Service/Raspkate.snk -------------------------------------------------------------------------------- /src/Raspkate.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Raspkate.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Raspkate.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4ea2377f-08c0-4f97-b369-98bc96dae0f4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Raspkate.Tests/Raspkate.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F1021F48-B8C0-418C-95AC-8089A8814F7F} 8 | Library 9 | Properties 10 | Raspkate.Tests 11 | Raspkate.Tests 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | 35 | 36 | Raspkate.snk 37 | 38 | 39 | 40 | ..\..\lib\nunit.framework.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {38bb78ef-cfa0-457a-b216-5b3aff7c5520} 60 | Raspkate 61 | 62 | 63 | 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /src/Raspkate.Tests/Raspkate.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate.Tests/Raspkate.snk -------------------------------------------------------------------------------- /src/Raspkate.Tests/RoutingTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Raspkate.Controllers.Routing; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Raspkate.Tests 10 | { 11 | [TestFixture] 12 | public class RoutingTests 13 | { 14 | [Test] 15 | public void ParseStaticRouteTest() 16 | { 17 | var route = RouteParser.Parse("api/customers/all"); 18 | Assert.AreEqual(3, route.Count); 19 | Assert.IsInstanceOf(route[0]); 20 | Assert.IsInstanceOf(route[1]); 21 | Assert.IsInstanceOf(route[2]); 22 | } 23 | 24 | [Test] 25 | public void ParseParameterRouteTest() 26 | { 27 | var route = RouteParser.Parse("api/customers/{id}"); 28 | Assert.AreEqual(3, route.Count); 29 | Assert.IsInstanceOf(route[0]); 30 | Assert.IsInstanceOf(route[1]); 31 | Assert.IsInstanceOf(route[2]); 32 | } 33 | 34 | [Test] 35 | public void ParseParameterRouteItemAtMiddlePositionTest() 36 | { 37 | var route = RouteParser.Parse("api/customers/{id}/orders"); 38 | Assert.AreEqual(4, route.Count); 39 | Assert.IsInstanceOf(route[0]); 40 | Assert.IsInstanceOf(route[1]); 41 | Assert.IsInstanceOf(route[2]); 42 | Assert.IsInstanceOf(route[3]); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Raspkate.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raspkate", "Raspkate\Raspkate.csproj", "{38BB78EF-CFA0-457A-B216-5B3AFF7C5520}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0DDC80C4-BA96-4773-8D89-FC8D2C2048E6}" 9 | ProjectSection(SolutionItems) = preProject 10 | build.bat = build.bat 11 | build.sh = build.sh 12 | EndProjectSection 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raspkate.Modules.Default", "Raspkate.Modules.Default\Raspkate.Modules.Default.csproj", "{3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raspkate.Modules.RaspberryPi", "Raspkate.Modules.RaspberryPi\Raspkate.Modules.RaspberryPi.csproj", "{7B1B80ED-D594-4908-8322-C3E76A05AF28}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raspkate.Service", "Raspkate.Service\Raspkate.Service.csproj", "{1C2E4FD6-39B4-4762-B32C-E3079856A227}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raspkate.Tests", "Raspkate.Tests\Raspkate.Tests.csproj", "{F1021F48-B8C0-418C-95AC-8089A8814F7F}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | All|Any CPU = All|Any CPU 25 | Debug|Any CPU = Debug|Any CPU 26 | Minimal|Any CPU = Minimal|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.All|Any CPU.ActiveCfg = Release|Any CPU 31 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.All|Any CPU.Build.0 = Release|Any CPU 32 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Minimal|Any CPU.ActiveCfg = Release|Any CPU 35 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Minimal|Any CPU.Build.0 = Release|Any CPU 36 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.All|Any CPU.ActiveCfg = Release|Any CPU 39 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.All|Any CPU.Build.0 = Release|Any CPU 40 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Minimal|Any CPU.ActiveCfg = Release|Any CPU 43 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Minimal|Any CPU.Build.0 = Release|Any CPU 44 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {3BF8382C-4FC9-482F-A4ED-B6EE4608DBF5}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.All|Any CPU.ActiveCfg = Release|Any CPU 47 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.All|Any CPU.Build.0 = Release|Any CPU 48 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.Minimal|Any CPU.ActiveCfg = Release|Any CPU 51 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {7B1B80ED-D594-4908-8322-C3E76A05AF28}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.All|Any CPU.ActiveCfg = Release|Any CPU 54 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.All|Any CPU.Build.0 = Release|Any CPU 55 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Minimal|Any CPU.ActiveCfg = Release|Any CPU 58 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Minimal|Any CPU.Build.0 = Release|Any CPU 59 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {1C2E4FD6-39B4-4762-B32C-E3079856A227}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.All|Any CPU.ActiveCfg = Release|Any CPU 62 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.Minimal|Any CPU.ActiveCfg = Release|Any CPU 65 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {F1021F48-B8C0-418C-95AC-8089A8814F7F}.Release|Any CPU.Build.0 = Release|Any CPU 67 | EndGlobalSection 68 | GlobalSection(SolutionProperties) = preSolution 69 | HideSolutionNode = FALSE 70 | EndGlobalSection 71 | EndGlobal 72 | -------------------------------------------------------------------------------- /src/Raspkate/Config/ConfigurationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Config 8 | { 9 | public class ConfigurationException : RaspkateException 10 | { 11 | public ConfigurationException() 12 | { } 13 | 14 | public ConfigurationException(string message) 15 | : base(message) 16 | { } 17 | 18 | public ConfigurationException(string format, params string[] args) 19 | : base(string.Format(format, args)) 20 | { } 21 | 22 | public ConfigurationException(string message, Exception innerException) 23 | : base(message, innerException) 24 | { } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Raspkate/Config/RaspkateConfig.csd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/Raspkate/Config/RaspkateConfig.csd.config: -------------------------------------------------------------------------------- 1 |  2 | 10 | 11 | 12 |
13 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Raspkate/Config/RaspkateConfig.csd.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Raspkate.Config 12 | { 13 | 14 | 15 | /// 16 | /// The RaspkateConfiguration Configuration Section. 17 | /// 18 | public partial class RaspkateConfiguration : global::System.Configuration.ConfigurationSection 19 | { 20 | 21 | #region Singleton Instance 22 | /// 23 | /// The XML name of the RaspkateConfiguration Configuration Section. 24 | /// 25 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 26 | internal const string RaspkateConfigurationSectionName = "raspkateConfiguration"; 27 | 28 | /// 29 | /// The XML path of the RaspkateConfiguration Configuration Section. 30 | /// 31 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 32 | internal const string RaspkateConfigurationSectionPath = "raspkateConfiguration"; 33 | 34 | /// 35 | /// Gets the RaspkateConfiguration instance. 36 | /// 37 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 38 | public static global::Raspkate.Config.RaspkateConfiguration Instance 39 | { 40 | get 41 | { 42 | return ((global::Raspkate.Config.RaspkateConfiguration)(global::System.Configuration.ConfigurationManager.GetSection(global::Raspkate.Config.RaspkateConfiguration.RaspkateConfigurationSectionPath))); 43 | } 44 | } 45 | #endregion 46 | 47 | #region Xmlns Property 48 | /// 49 | /// The XML name of the property. 50 | /// 51 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 52 | internal const string XmlnsPropertyName = "xmlns"; 53 | 54 | /// 55 | /// Gets the XML namespace of this Configuration Section. 56 | /// 57 | /// 58 | /// This property makes sure that if the configuration file contains the XML namespace, 59 | /// the parser doesn't throw an exception because it encounters the unknown "xmlns" attribute. 60 | /// 61 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 62 | [global::System.Configuration.ConfigurationPropertyAttribute(global::Raspkate.Config.RaspkateConfiguration.XmlnsPropertyName, IsRequired=false, IsKey=false, IsDefaultCollection=false)] 63 | public string Xmlns 64 | { 65 | get 66 | { 67 | return ((string)(base[global::Raspkate.Config.RaspkateConfiguration.XmlnsPropertyName])); 68 | } 69 | } 70 | #endregion 71 | 72 | #region IsReadOnly override 73 | /// 74 | /// Gets a value indicating whether the element is read-only. 75 | /// 76 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 77 | public override bool IsReadOnly() 78 | { 79 | return false; 80 | } 81 | #endregion 82 | 83 | #region Prefix Property 84 | /// 85 | /// The XML name of the property. 86 | /// 87 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 88 | internal const string PrefixPropertyName = "prefix"; 89 | 90 | /// 91 | /// Gets or sets the Prefix. 92 | /// 93 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 94 | [global::System.ComponentModel.DescriptionAttribute("The Prefix.")] 95 | [global::System.Configuration.ConfigurationPropertyAttribute(global::Raspkate.Config.RaspkateConfiguration.PrefixPropertyName, IsRequired=true, IsKey=false, IsDefaultCollection=false)] 96 | public virtual string Prefix 97 | { 98 | get 99 | { 100 | return ((string)(base[global::Raspkate.Config.RaspkateConfiguration.PrefixPropertyName])); 101 | } 102 | set 103 | { 104 | base[global::Raspkate.Config.RaspkateConfiguration.PrefixPropertyName] = value; 105 | } 106 | } 107 | #endregion 108 | 109 | #region Modules Property 110 | /// 111 | /// The XML name of the property. 112 | /// 113 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 114 | internal const string ModulesPropertyName = "modules"; 115 | 116 | /// 117 | /// Gets or sets the Modules. 118 | /// 119 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 120 | [global::System.ComponentModel.DescriptionAttribute("The Modules.")] 121 | [global::System.Configuration.ConfigurationPropertyAttribute(global::Raspkate.Config.RaspkateConfiguration.ModulesPropertyName, IsRequired=true, IsKey=false, IsDefaultCollection=false)] 122 | public virtual global::Raspkate.Config.ModuleElementCollection Modules 123 | { 124 | get 125 | { 126 | return ((global::Raspkate.Config.ModuleElementCollection)(base[global::Raspkate.Config.RaspkateConfiguration.ModulesPropertyName])); 127 | } 128 | set 129 | { 130 | base[global::Raspkate.Config.RaspkateConfiguration.ModulesPropertyName] = value; 131 | } 132 | } 133 | #endregion 134 | } 135 | } 136 | namespace Raspkate.Config 137 | { 138 | 139 | 140 | /// 141 | /// The ModuleElement Configuration Element. 142 | /// 143 | public partial class ModuleElement : global::System.Configuration.ConfigurationElement 144 | { 145 | 146 | #region IsReadOnly override 147 | /// 148 | /// Gets a value indicating whether the element is read-only. 149 | /// 150 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 151 | public override bool IsReadOnly() 152 | { 153 | return false; 154 | } 155 | #endregion 156 | 157 | #region Path Property 158 | /// 159 | /// The XML name of the property. 160 | /// 161 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 162 | internal const string PathPropertyName = "path"; 163 | 164 | /// 165 | /// Gets or sets the Path. 166 | /// 167 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 168 | [global::System.ComponentModel.DescriptionAttribute("The Path.")] 169 | [global::System.Configuration.ConfigurationPropertyAttribute(global::Raspkate.Config.ModuleElement.PathPropertyName, IsRequired=true, IsKey=true, IsDefaultCollection=false)] 170 | public virtual string Path 171 | { 172 | get 173 | { 174 | return ((string)(base[global::Raspkate.Config.ModuleElement.PathPropertyName])); 175 | } 176 | set 177 | { 178 | base[global::Raspkate.Config.ModuleElement.PathPropertyName] = value; 179 | } 180 | } 181 | #endregion 182 | 183 | #region IsRelative Property 184 | /// 185 | /// The XML name of the property. 186 | /// 187 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 188 | internal const string IsRelativePropertyName = "relative"; 189 | 190 | /// 191 | /// Gets or sets the IsRelative. 192 | /// 193 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 194 | [global::System.ComponentModel.DescriptionAttribute("The IsRelative.")] 195 | [global::System.Configuration.ConfigurationPropertyAttribute(global::Raspkate.Config.ModuleElement.IsRelativePropertyName, IsRequired=false, IsKey=false, IsDefaultCollection=false, DefaultValue=true)] 196 | public virtual bool IsRelative 197 | { 198 | get 199 | { 200 | return ((bool)(base[global::Raspkate.Config.ModuleElement.IsRelativePropertyName])); 201 | } 202 | set 203 | { 204 | base[global::Raspkate.Config.ModuleElement.IsRelativePropertyName] = value; 205 | } 206 | } 207 | #endregion 208 | } 209 | } 210 | namespace Raspkate.Config 211 | { 212 | 213 | 214 | /// 215 | /// A collection of ModuleElement instances. 216 | /// 217 | [global::System.Configuration.ConfigurationCollectionAttribute(typeof(global::Raspkate.Config.ModuleElement), CollectionType=global::System.Configuration.ConfigurationElementCollectionType.AddRemoveClearMapAlternate, AddItemName="add", RemoveItemName="remove", ClearItemsName="clear")] 218 | public partial class ModuleElementCollection : global::System.Configuration.ConfigurationElementCollection 219 | { 220 | 221 | #region Constants 222 | /// 223 | /// The XML name of the individual instances in this collection. 224 | /// 225 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 226 | internal const string ModuleElementPropertyName = "module"; 227 | #endregion 228 | 229 | #region Overrides 230 | /// 231 | /// Gets the type of the . 232 | /// 233 | /// The of this collection. 234 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 235 | public override global::System.Configuration.ConfigurationElementCollectionType CollectionType 236 | { 237 | get 238 | { 239 | return global::System.Configuration.ConfigurationElementCollectionType.AddRemoveClearMapAlternate; 240 | } 241 | } 242 | 243 | /// 244 | /// Gets the name used to identify this collection of elements 245 | /// 246 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 247 | protected override string ElementName 248 | { 249 | get 250 | { 251 | return global::Raspkate.Config.ModuleElementCollection.ModuleElementPropertyName; 252 | } 253 | } 254 | 255 | /// 256 | /// Indicates whether the specified exists in the . 257 | /// 258 | /// The name of the element to verify. 259 | /// 260 | /// if the element exists in the collection; otherwise, . 261 | /// 262 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 263 | protected override bool IsElementName(string elementName) 264 | { 265 | return (elementName == global::Raspkate.Config.ModuleElementCollection.ModuleElementPropertyName); 266 | } 267 | 268 | /// 269 | /// Gets the element key for the specified configuration element. 270 | /// 271 | /// The to return the key for. 272 | /// 273 | /// An that acts as the key for the specified . 274 | /// 275 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 276 | protected override object GetElementKey(global::System.Configuration.ConfigurationElement element) 277 | { 278 | return ((global::Raspkate.Config.ModuleElement)(element)).Path; 279 | } 280 | 281 | /// 282 | /// Creates a new . 283 | /// 284 | /// 285 | /// A new . 286 | /// 287 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 288 | protected override global::System.Configuration.ConfigurationElement CreateNewElement() 289 | { 290 | return new global::Raspkate.Config.ModuleElement(); 291 | } 292 | #endregion 293 | 294 | #region Indexer 295 | /// 296 | /// Gets the at the specified index. 297 | /// 298 | /// The index of the to retrieve. 299 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 300 | public global::Raspkate.Config.ModuleElement this[int index] 301 | { 302 | get 303 | { 304 | return ((global::Raspkate.Config.ModuleElement)(base.BaseGet(index))); 305 | } 306 | } 307 | 308 | /// 309 | /// Gets the with the specified key. 310 | /// 311 | /// The key of the to retrieve. 312 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 313 | public global::Raspkate.Config.ModuleElement this[object path] 314 | { 315 | get 316 | { 317 | return ((global::Raspkate.Config.ModuleElement)(base.BaseGet(path))); 318 | } 319 | } 320 | #endregion 321 | 322 | #region Add 323 | /// 324 | /// Adds the specified to the . 325 | /// 326 | /// The to add. 327 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 328 | public void Add(global::Raspkate.Config.ModuleElement module) 329 | { 330 | base.BaseAdd(module); 331 | } 332 | #endregion 333 | 334 | #region Remove 335 | /// 336 | /// Removes the specified from the . 337 | /// 338 | /// The to remove. 339 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 340 | public void Remove(global::Raspkate.Config.ModuleElement module) 341 | { 342 | base.BaseRemove(this.GetElementKey(module)); 343 | } 344 | #endregion 345 | 346 | #region GetItem 347 | /// 348 | /// Gets the at the specified index. 349 | /// 350 | /// The index of the to retrieve. 351 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 352 | public global::Raspkate.Config.ModuleElement GetItemAt(int index) 353 | { 354 | return ((global::Raspkate.Config.ModuleElement)(base.BaseGet(index))); 355 | } 356 | 357 | /// 358 | /// Gets the with the specified key. 359 | /// 360 | /// The key of the to retrieve. 361 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 362 | public global::Raspkate.Config.ModuleElement GetItemByKey(string path) 363 | { 364 | return ((global::Raspkate.Config.ModuleElement)(base.BaseGet(((object)(path))))); 365 | } 366 | #endregion 367 | 368 | #region IsReadOnly override 369 | /// 370 | /// Gets a value indicating whether the element is read-only. 371 | /// 372 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationSectionDesigner.CsdFileGenerator", "2.0.1.7")] 373 | public override bool IsReadOnly() 374 | { 375 | return false; 376 | } 377 | #endregion 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /src/Raspkate/Config/RaspkateConfig.csd.diagram: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Raspkate/Config/RaspkateConfig.csd.xsd: -------------------------------------------------------------------------------- 1 |  2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | The Modules. 17 | 18 | 19 | 20 | 21 | 22 | The Prefix. 23 | 24 | 25 | 26 | 27 | 28 | 29 | The Path. 30 | 31 | 32 | 33 | 34 | The IsRelative. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | The ModuleElement Configuration Element. 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | The Path. 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/ControllerException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | public class ControllerException : RaspkateException 10 | { 11 | public ControllerException() 12 | { } 13 | 14 | public ControllerException(string message) 15 | : base(message) 16 | { } 17 | 18 | public ControllerException(string format, params string[] args) 19 | : base(string.Format(format, args)) 20 | { } 21 | 22 | public ControllerException(string message, Exception innerException) 23 | : base(message, innerException) 24 | { } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/FromBodyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | [AttributeUsage(AttributeTargets.Parameter)] 10 | public sealed class FromBodyAttribute : Attribute 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/HttpGetAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | /// 10 | /// Represents the HTTP GET method. 11 | /// 12 | [AttributeUsage(AttributeTargets.Method)] 13 | public sealed class HttpGetAttribute : HttpMethodAttribute 14 | { 15 | /// 16 | /// Initializes a new instancce of class. 17 | /// 18 | public HttpGetAttribute() 19 | : base("GET") 20 | { } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/HttpMethodAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | /// 10 | /// Represents an HTTP method. 11 | /// 12 | [AttributeUsage(AttributeTargets.Method, Inherited=true)] 13 | public abstract class HttpMethodAttribute : Attribute 14 | { 15 | /// 16 | /// Initializes a new instance of class. 17 | /// 18 | /// Name of the HTTP method in uppercase, e.g. GET, POST, PUT, etc. 19 | protected HttpMethodAttribute(string methodName) 20 | { 21 | this.MethodName = methodName; 22 | } 23 | 24 | /// 25 | /// Gets the name of current HTTP method, in uppercase, e.g. GET, POST, PUT, etc. 26 | /// 27 | public string MethodName { get; private set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/HttpPostAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | /// 10 | /// Represents the HTTP POST method. 11 | /// 12 | [AttributeUsage(AttributeTargets.Method)] 13 | public sealed class HttpPostAttribute : HttpMethodAttribute 14 | { 15 | /// 16 | /// Initializes a new instace of class. 17 | /// 18 | public HttpPostAttribute() 19 | : base("POST") 20 | { } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/RaspkateController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Controllers 9 | { 10 | /// 11 | /// Represents the base class of Raspkate controllers. 12 | /// 13 | public abstract class RaspkateController : IDisposable 14 | { 15 | /// 16 | /// The internal object used for locking and synchronzation. 17 | /// 18 | internal readonly object _syncObject = new object(); 19 | 20 | ~RaspkateController() 21 | { 22 | this.Dispose(false); 23 | } 24 | 25 | public void Dispose() 26 | { 27 | this.Dispose(true); 28 | GC.SuppressFinalize(this); 29 | } 30 | 31 | protected virtual void Dispose(bool disposing) { } 32 | 33 | protected dynamic Error(object value) 34 | { 35 | return Error(HttpStatusCode.InternalServerError, value); 36 | } 37 | 38 | protected dynamic Error(HttpStatusCode httpStatusCode, object value) 39 | { 40 | return new 41 | { 42 | HttpStatusCode = httpStatusCode, 43 | Value = value 44 | }; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/RouteAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | [AttributeUsage(AttributeTargets.Method)] 10 | public sealed class RouteAttribute : Attribute 11 | { 12 | public RouteAttribute(string name) 13 | { 14 | this.Name = name; 15 | } 16 | 17 | public string Name { get; private set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/RoutePrefixAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | [AttributeUsage(AttributeTargets.Class)] 10 | public sealed class RoutePrefixAttribute : Attribute 11 | { 12 | public RoutePrefixAttribute(string prefix) 13 | { 14 | this.Prefix = prefix; 15 | } 16 | 17 | public string Prefix { get; private set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/LiteralRouteItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Controllers.Routing 9 | { 10 | [RouteItem(@"^(?\w+)$")] 11 | internal sealed class LiteralRouteItem : RouteItem 12 | { 13 | public override bool Prepare(string itemTemplate) 14 | { 15 | var match = this.Attribute.MatchItemTemplate(itemTemplate); 16 | if (match.Success && match.Groups[NameGroup] != null) 17 | { 18 | this.Name = match.Groups[NameGroup].Value; 19 | if (!string.IsNullOrEmpty(this.Name)) 20 | { 21 | return true; 22 | } 23 | } 24 | return false; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/ParameterRouteItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Controllers.Routing 9 | { 10 | [RouteItem(@"^{(?\w+)(:(?\w+)(:(?.+))?)?}$")] 11 | internal sealed class ParameterRouteItem : RouteItem 12 | { 13 | public const string TypeGroup = "type"; 14 | public const string ConstraintGroup = "constraint"; 15 | 16 | public override bool Prepare(string itemTemplate) 17 | { 18 | var match = this.Attribute.MatchItemTemplate(itemTemplate); 19 | if (match.Success && match.Groups[NameGroup] != null) 20 | { 21 | this.Name = match.Groups[NameGroup].Value; 22 | if (string.IsNullOrEmpty(this.Name)) 23 | { 24 | return false; 25 | } 26 | var parameterTypeName = match.Groups[TypeGroup] == null ? null : match.Groups[TypeGroup].Value; 27 | if (!string.IsNullOrEmpty(parameterTypeName)) 28 | { 29 | this.ParameterType = NameToType(parameterTypeName); 30 | } 31 | else 32 | { 33 | this.ParameterType = typeof(object); 34 | } 35 | 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | public object GetValue(string input) 42 | { 43 | try 44 | { 45 | if (this.ParameterType != null) 46 | return Convert.ChangeType(input, this.ParameterType); 47 | } 48 | catch 49 | { 50 | 51 | } 52 | return null; 53 | } 54 | 55 | public Type ParameterType { get; private set; } 56 | 57 | private static Type NameToType(string name) 58 | { 59 | var cname = name.ToLower(); 60 | switch(cname) 61 | { 62 | case "int": 63 | return typeof(int); 64 | case "bool": 65 | return typeof(bool); 66 | case "datetime": 67 | return typeof(DateTime); 68 | case "decimal": 69 | return typeof(decimal); 70 | case "double": 71 | return typeof(double); 72 | case "float": 73 | return typeof(float); 74 | case "guid": 75 | return typeof(Guid); 76 | default: 77 | return typeof(string); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/Route.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers.Routing 8 | { 9 | internal sealed class Route : IList 10 | { 11 | private readonly List items = new List(); 12 | 13 | internal Route() { } 14 | 15 | 16 | public int IndexOf(RouteItem item) 17 | { 18 | return items.IndexOf(item); 19 | } 20 | 21 | public void Insert(int index, RouteItem item) 22 | { 23 | items.Insert(index, item); 24 | } 25 | 26 | public void RemoveAt(int index) 27 | { 28 | items.RemoveAt(index); 29 | } 30 | 31 | public RouteItem this[int index] 32 | { 33 | get 34 | { 35 | return items[index]; 36 | } 37 | set 38 | { 39 | items[index] = value; 40 | } 41 | } 42 | 43 | public void Add(RouteItem item) 44 | { 45 | items.Add(item); 46 | } 47 | 48 | public void Clear() 49 | { 50 | items.Clear(); 51 | } 52 | 53 | public bool Contains(RouteItem item) 54 | { 55 | return items.Contains(item); 56 | } 57 | 58 | public void CopyTo(RouteItem[] array, int arrayIndex) 59 | { 60 | items.CopyTo(array, arrayIndex); 61 | } 62 | 63 | public int Count 64 | { 65 | get { return items.Count; } 66 | } 67 | 68 | public bool IsReadOnly 69 | { 70 | get { return false; } 71 | } 72 | 73 | public bool Remove(RouteItem item) 74 | { 75 | return items.Remove(item); 76 | } 77 | 78 | public IEnumerator GetEnumerator() 79 | { 80 | return items.GetEnumerator(); 81 | } 82 | 83 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 84 | { 85 | return items.GetEnumerator(); 86 | } 87 | 88 | public bool TryGetValue(string input, out RouteValueCollection values) 89 | { 90 | values = new RouteValueCollection(); 91 | var splittedInput = input.Split('/'); 92 | if (this.Count == 0) 93 | return false; 94 | if (this.Count != splittedInput.Length) 95 | return false; 96 | int idx = 0; 97 | foreach(var splittedInputItem in splittedInput) 98 | { 99 | var literalRouteItem = this[idx] as LiteralRouteItem; 100 | if (literalRouteItem != null) 101 | { 102 | if (literalRouteItem.Name == splittedInputItem) 103 | { 104 | idx++; 105 | continue; 106 | } 107 | else 108 | return false; 109 | } 110 | var parameterRouteItem = this[idx] as ParameterRouteItem; 111 | if (parameterRouteItem != null) 112 | { 113 | var parameterValue = parameterRouteItem.GetValue(splittedInputItem); 114 | if (parameterValue != null) 115 | { 116 | values.Add(parameterRouteItem.Name, parameterValue); 117 | idx++; 118 | continue; 119 | } 120 | else 121 | return false; 122 | } 123 | idx++; 124 | } 125 | return true; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/RouteItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Controllers.Routing 9 | { 10 | /// 11 | /// Represents a particular component is a route string. 12 | /// 13 | internal abstract class RouteItem 14 | { 15 | public const string NameGroup = "name"; 16 | 17 | public abstract bool Prepare(string itemTemplate); 18 | 19 | public string Name { get; protected set; } 20 | 21 | protected RouteItemAttribute Attribute 22 | { 23 | get 24 | { 25 | return (RouteItemAttribute)this.GetType().GetCustomAttributes(typeof(RouteItemAttribute), false).FirstOrDefault(); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/RouteItemAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace Raspkate.Controllers.Routing 9 | { 10 | [AttributeUsage(AttributeTargets.Class)] 11 | internal sealed class RouteItemAttribute : Attribute 12 | { 13 | public string Template { get; private set; } 14 | 15 | public RouteItemAttribute(string template) 16 | { 17 | this.Template = template; 18 | } 19 | 20 | public Match MatchItemTemplate(string itemTemplate) 21 | { 22 | return new Regex(this.Template).Match(itemTemplate); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/RouteParseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers.Routing 8 | { 9 | public class RouteParseException : RaspkateException 10 | { 11 | public RouteParseException() 12 | { } 13 | 14 | public RouteParseException(string message) 15 | : base(message) 16 | { } 17 | 18 | public RouteParseException(string format, params object[] args) 19 | : base(string.Format(format, args)) 20 | { } 21 | 22 | public RouteParseException(string message, Exception innerException) 23 | : base(message, innerException) 24 | { } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/RouteParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers.Routing 8 | { 9 | internal static class RouteParser 10 | { 11 | private static readonly List RegisteredRouteTypes = new List { typeof(LiteralRouteItem), typeof(ParameterRouteItem) }; 12 | 13 | public static Route Parse(string routePattern) 14 | { 15 | var splittedItems = routePattern.Split('/'); 16 | Route route = new Route(); 17 | foreach (var splittedItem in splittedItems) 18 | { 19 | var routeItemType = RegisteredRouteTypes.FirstOrDefault(x => x.IsDefined(typeof(RouteItemAttribute), false) && 20 | ((RouteItemAttribute)(x.GetCustomAttributes(typeof(RouteItemAttribute), false).First())).MatchItemTemplate(splittedItem).Success); 21 | 22 | if (routeItemType == null) 23 | { 24 | throw new RouteParseException("There is no registered route item that can handle the item template \"{0}\".", splittedItem); 25 | } 26 | 27 | var routeItem = (RouteItem)Activator.CreateInstance(routeItemType); 28 | if (!routeItem.Prepare(splittedItem)) 29 | { 30 | throw new RouteParseException("Failed to prepare the route item for item template \"{0}\", the route item might not be able to extract the required information.", splittedItem); 31 | } 32 | route.Add(routeItem); 33 | } 34 | return route; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/Routing/RouteValueCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers.Routing 8 | { 9 | internal sealed class RouteValueCollection : IDictionary 10 | { 11 | private readonly Dictionary values = new Dictionary(); 12 | 13 | public void Add(string key, object value) 14 | { 15 | values.Add(key, value); 16 | } 17 | 18 | public bool ContainsKey(string key) 19 | { 20 | return values.ContainsKey(key); 21 | } 22 | 23 | public ICollection Keys 24 | { 25 | get { return values.Keys; } 26 | } 27 | 28 | public bool Remove(string key) 29 | { 30 | return values.Remove(key); 31 | } 32 | 33 | public bool TryGetValue(string key, out object value) 34 | { 35 | return values.TryGetValue(key, out value); 36 | } 37 | 38 | public ICollection Values 39 | { 40 | get { return values.Values; } 41 | } 42 | 43 | public object this[string key] 44 | { 45 | get 46 | { 47 | return values[key]; 48 | } 49 | set 50 | { 51 | values[key] = value; 52 | } 53 | } 54 | 55 | public void Add(KeyValuePair item) 56 | { 57 | values.Add(item.Key, item.Value); 58 | } 59 | 60 | public void Clear() 61 | { 62 | values.Clear(); 63 | } 64 | 65 | public bool Contains(KeyValuePair item) 66 | { 67 | return values.Contains(item); 68 | } 69 | 70 | public void CopyTo(KeyValuePair[] array, int arrayIndex) 71 | { 72 | ((ICollection>)values).CopyTo(array, arrayIndex); 73 | } 74 | 75 | public int Count 76 | { 77 | get { return values.Count; } 78 | } 79 | 80 | public bool IsReadOnly 81 | { 82 | get { return false; } 83 | } 84 | 85 | public bool Remove(KeyValuePair item) 86 | { 87 | return values.Remove(item.Key); 88 | } 89 | 90 | public IEnumerator> GetEnumerator() 91 | { 92 | return values.GetEnumerator(); 93 | } 94 | 95 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 96 | { 97 | return values.GetEnumerator(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Raspkate/Controllers/SynchronizedAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate.Controllers 8 | { 9 | [AttributeUsage(AttributeTargets.Class)] 10 | public sealed class SynchronizedAttribute : Attribute 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Raspkate/HandlerProcessResult.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Raspkate 10 | { 11 | /// 12 | /// Represents the processing result of a . 13 | /// 14 | public sealed class HandlerProcessResult 15 | { 16 | 17 | public static readonly HandlerProcessResult Success = new HandlerProcessResult(HttpStatusCode.OK, null, null); 18 | 19 | public static readonly Encoding ContentEncoding = Encoding.UTF8; 20 | 21 | public HttpStatusCode StatusCode { get; private set; } 22 | 23 | [JsonIgnore] 24 | public byte[] Content { get; private set; } 25 | 26 | public string ContentBase64 27 | { 28 | get 29 | { 30 | if (this.Content == null) 31 | { 32 | return null; 33 | } 34 | return Convert.ToBase64String(this.Content); 35 | } 36 | } 37 | 38 | public string ContentType { get; private set; } 39 | 40 | private HandlerProcessResult(HttpStatusCode statusCode, string contentType, byte[] content) 41 | { 42 | this.StatusCode = statusCode; 43 | this.Content = content; 44 | this.ContentType = contentType; 45 | } 46 | 47 | public static HandlerProcessResult Text(HttpStatusCode statusCode, string content) 48 | { 49 | var contentBytes = ContentEncoding.GetBytes(content); 50 | return new HandlerProcessResult(statusCode, "text/plain", contentBytes); 51 | } 52 | 53 | public static HandlerProcessResult Json(HttpStatusCode statusCode, string jsonContent) 54 | { 55 | var contentBytes = ContentEncoding.GetBytes(jsonContent); 56 | return new HandlerProcessResult(statusCode, "application/json", contentBytes); 57 | } 58 | 59 | public static HandlerProcessResult File(HttpStatusCode statusCode, string contentType, byte[] content) 60 | { 61 | return new HandlerProcessResult(statusCode, contentType, content); 62 | } 63 | 64 | public static HandlerProcessResult Exception(HttpStatusCode statusCode, Exception ex) 65 | { 66 | return Text(statusCode, ex.ToString()); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Raspkate/Handlers/ControllerHandler.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Raspkate.Controllers; 3 | using Raspkate.Controllers.Routing; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Dynamic; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Reflection; 10 | using System.Text; 11 | using System.Text.RegularExpressions; 12 | using System.Threading.Tasks; 13 | 14 | namespace Raspkate.Handlers 15 | { 16 | /// 17 | /// Represents the handler that can handle RESTful API request and process the request by registered controllers. 18 | /// 19 | public sealed class ControllerHandler : RaspkateHandler 20 | { 21 | private readonly Regex fileNameRegularExpression = new Regex(FileHandler.Pattern); 22 | private readonly List controllerRegistrations = new List(); 23 | private readonly Dictionary synchronizedControllers = new Dictionary(); 24 | private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 25 | 26 | public ControllerHandler(string name, IEnumerable types) 27 | : base(name) 28 | { 29 | if (types != null) 30 | { 31 | var controllerTypes = from type in types 32 | where type.IsSubclassOf(typeof(RaspkateController)) 33 | select type; 34 | foreach(var controllerType in controllerTypes) 35 | { 36 | this.RegisterControllerType(controllerType); 37 | log.InfoFormat("Controller type \"{0}\" registered successfully.", controllerType); 38 | } 39 | } 40 | } 41 | 42 | public override void OnUnregistered() 43 | { 44 | foreach(var controller in synchronizedControllers.Values) 45 | { 46 | controller.Dispose(); 47 | } 48 | } 49 | 50 | public override bool ShouldHandle(HttpListenerRequest request) 51 | { 52 | return request.RawUrl != "/" && 53 | !this.fileNameRegularExpression.Match(request.RawUrl.Trim('\\', '/', '?')).Success; 54 | } 55 | 56 | public override HandlerProcessResult Process(HttpListenerRequest request) 57 | { 58 | try 59 | { 60 | var requestedUri = request.RawUrl.Trim('/'); 61 | if (requestedUri.Contains('?')) 62 | { 63 | requestedUri = requestedUri.Substring(0, requestedUri.IndexOf('?')); 64 | } 65 | foreach (var controllerRegistration in this.controllerRegistrations) 66 | { 67 | // Checks the HTTP method. 68 | var httpMethodName = controllerRegistration.ControllerMethod.GetCustomAttribute().MethodName; 69 | if (request.HttpMethod != httpMethodName) 70 | { 71 | log.DebugFormat("The HTTP method in the request \"{0}\" is different from the one defined on the controller method (Requested {1} but {2}).", 72 | requestedUri, request.HttpMethod, httpMethodName); 73 | continue; 74 | } 75 | 76 | // Checks if the current controller registration matches the requested route. 77 | RouteValueCollection values; 78 | if (controllerRegistration.Route.TryGetValue(requestedUri, out values)) 79 | { 80 | // If successfully get the route values, then bind the parameter. 81 | List parameterValues = new List(); 82 | foreach (var parameter in controllerRegistration.ControllerMethod.GetParameters()) 83 | { 84 | if (parameter.IsDefined(typeof(FromBodyAttribute))) 85 | { 86 | if (controllerRegistration.ControllerMethod.IsDefined(typeof(HttpPostAttribute))) 87 | { 88 | var bodyContent = string.Empty; 89 | if (request.ContentLength64 > 0) 90 | { 91 | var bytes = new byte[request.ContentLength64]; 92 | request.InputStream.Read(bytes, 0, (int)request.ContentLength64); 93 | bodyContent = request.ContentEncoding.GetString(bytes); 94 | } 95 | parameterValues.Add(JsonConvert.DeserializeObject(bodyContent)); 96 | } 97 | else 98 | { 99 | throw new ControllerException("Parameter \"{0}\" of method {1}.{2} has the FromBodyAttribute defined, which is not allowed in an HTTP GET method.", parameter.Name, controllerRegistration.ControllerType.Name, controllerRegistration.ControllerMethod.Name); 100 | } 101 | } 102 | else 103 | { 104 | if (values.ContainsKey(parameter.Name)) 105 | { 106 | var v = values[parameter.Name]; 107 | if (v.GetType().Equals(parameter.ParameterType)) 108 | { 109 | parameterValues.Add(values[parameter.Name]); 110 | } 111 | else 112 | { 113 | parameterValues.Add(Convert.ChangeType(v, parameter.ParameterType)); 114 | } 115 | } 116 | else 117 | { 118 | throw new ControllerException("Parameter binding failed: Unrecognized parameter \"{0}\" defined in the controller method {1}.{2}.", 119 | parameter.Name, 120 | controllerRegistration.ControllerType.Name, 121 | controllerRegistration.ControllerMethod.Name); 122 | } 123 | } 124 | } 125 | 126 | // Call the controller method 127 | RaspkateController controller; 128 | bool synchronized = false; 129 | if (controllerRegistration.ControllerType.IsDefined(typeof(SynchronizedAttribute)) && 130 | synchronizedControllers.ContainsKey(controllerRegistration.ControllerType.AssemblyQualifiedName)) 131 | { 132 | controller = synchronizedControllers[controllerRegistration.ControllerType.AssemblyQualifiedName]; 133 | synchronized = true; 134 | } 135 | else 136 | { 137 | controller = (RaspkateController)Activator.CreateInstance(controllerRegistration.ControllerType); 138 | } 139 | 140 | if (controller != null) 141 | { 142 | if (synchronized) 143 | { 144 | lock (controller._syncObject) 145 | { 146 | return InvokeControllerMethod(controllerRegistration, parameterValues, controller); 147 | } 148 | } 149 | else 150 | { 151 | using (controller) 152 | { 153 | return InvokeControllerMethod(controllerRegistration, parameterValues, controller); 154 | } 155 | } 156 | } 157 | } 158 | } 159 | //throw new ControllerException("No registered controller can handle the request with route \"{0}\".", requestedUri); 160 | var message = string.Format("No controller registered to the ControllerHandler (\"{0}\") can handle the request with route \"{1}\".", this.Name, requestedUri); 161 | return HandlerProcessResult.Text(HttpStatusCode.BadRequest, message); 162 | } 163 | catch (ControllerException ex) 164 | { 165 | log.Warn("Unable to proceed with the given request.", ex); 166 | return HandlerProcessResult.Exception(HttpStatusCode.BadRequest, ex); 167 | } 168 | catch (Exception ex) 169 | { 170 | log.Error("Error occurred when processing the request.", ex); 171 | return HandlerProcessResult.Exception(HttpStatusCode.InternalServerError, ex); 172 | } 173 | } 174 | 175 | private static HandlerProcessResult InvokeControllerMethod(ControllerRegistration controllerRegistration, List parameterValues, RaspkateController controller) 176 | { 177 | if (controllerRegistration.ControllerMethod.ReturnType == typeof(void)) 178 | { 179 | controllerRegistration.ControllerMethod.Invoke(controller, parameterValues.ToArray()); 180 | return HandlerProcessResult.Success; 181 | } 182 | else 183 | { 184 | var result = controllerRegistration.ControllerMethod.Invoke(controller, parameterValues.ToArray()); 185 | var httpStatusCodeProperty = result.GetType().GetProperty("HttpStatusCode"); 186 | var valueProperty = result.GetType().GetProperty("Value"); 187 | if (httpStatusCodeProperty != null && valueProperty != null) 188 | { 189 | var httpStatusCode = (HttpStatusCode)httpStatusCodeProperty.GetValue(result); 190 | var valueObj = valueProperty.GetValue(result); 191 | return HandlerProcessResult.Json(httpStatusCode, JsonConvert.SerializeObject(valueObj)); 192 | } 193 | else 194 | { 195 | var responseString = JsonConvert.SerializeObject(result); 196 | return HandlerProcessResult.Json(HttpStatusCode.OK, responseString); 197 | } 198 | } 199 | } 200 | 201 | private void RegisterControllerType(Type controllerType) 202 | { 203 | string routePrefix = string.Empty; 204 | if (controllerType.IsDefined(typeof(RoutePrefixAttribute))) 205 | { 206 | routePrefix = (controllerType.GetCustomAttributes(typeof(RoutePrefixAttribute), false).First() as RoutePrefixAttribute).Prefix; 207 | } 208 | 209 | var methodQuery = from m in controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance) 210 | where m.IsDefined(typeof(HttpMethodAttribute), true) 211 | select new 212 | { 213 | Route = m.IsDefined(typeof(RouteAttribute)) ? m.GetCustomAttribute().Name : m.Name, 214 | MethodInfo = m 215 | }; 216 | foreach (var methodQueryItem in methodQuery) 217 | { 218 | string routeString = string.Empty; 219 | Route route; 220 | if (methodQueryItem.Route.StartsWith("!")) 221 | { 222 | routeString = methodQueryItem.Route.Substring(1); 223 | } 224 | else 225 | { 226 | routeString = routePrefix; 227 | if (!string.IsNullOrEmpty(routeString) && !routeString.EndsWith("/")) 228 | routeString += "/"; 229 | routeString += methodQueryItem.Route; 230 | } 231 | try 232 | { 233 | route = RouteParser.Parse(routeString); 234 | } 235 | catch (RouteParseException rpe) 236 | { 237 | log.Warn(string.Format("Route parsing failed, ignoring the decorated controller method. (Route: \"{0}\", Method:{1}.{2})", 238 | routeString, 239 | controllerType.Name, 240 | methodQueryItem.MethodInfo.Name), rpe); 241 | 242 | continue; 243 | } 244 | 245 | this.controllerRegistrations.Add(new ControllerRegistration 246 | { 247 | ControllerMethod = methodQueryItem.MethodInfo, 248 | ControllerType = controllerType, 249 | Route = route, 250 | RouteTemplate = routeString 251 | }); 252 | 253 | if (controllerType.IsDefined(typeof(SynchronizedAttribute)) && !synchronizedControllers.ContainsKey(controllerType.AssemblyQualifiedName)) 254 | { 255 | synchronizedControllers.Add(controllerType.AssemblyQualifiedName, (RaspkateController)Activator.CreateInstance(controllerType)); 256 | } 257 | 258 | log.DebugFormat("Route \"{0}\" registered for controller method {1}.{2}.", routeString, controllerType.Name, methodQueryItem.MethodInfo.Name); 259 | } 260 | } 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/Raspkate/Handlers/ControllerRegistration.cs: -------------------------------------------------------------------------------- 1 | using Raspkate.Controllers.Routing; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Raspkate.Handlers 10 | { 11 | /// 12 | /// Represents the registration of a controller information. 13 | /// 14 | internal sealed class ControllerRegistration 15 | { 16 | /// 17 | /// Gets or sets the route template. 18 | /// 19 | public string RouteTemplate { get; set; } 20 | 21 | /// 22 | /// Gets or sets an instance of which represents a route, 23 | /// and can extract the values from that. 24 | /// 25 | public Route Route { get; set; } 26 | 27 | /// 28 | /// Gets or sets the of the controller. 29 | /// 30 | public Type ControllerType { get; set; } 31 | 32 | /// 33 | /// Gets or sets the which represents a method 34 | /// in the controller that corresponds to the route. 35 | /// 36 | public MethodInfo ControllerMethod { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Raspkate/Handlers/FileHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.IO; 3 | using System.Net; 4 | using System.Text.RegularExpressions; 5 | using System.Threading; 6 | using System.Collections.Generic; 7 | using System.Reflection; 8 | using System; 9 | using Raspkate.Config; 10 | 11 | namespace Raspkate.Handlers 12 | { 13 | public sealed class FileHandler : RaspkateHandler 14 | { 15 | internal const string Pattern = 16 | @"^(?/?(\w(\w|\-|\s)*/)*(\w|\-)+(\.(\w|\-)+)*\.\w+)(\?(?\w+=(\w|\-)+(&\w+=(\w|\-)+)*))?$"; 17 | 18 | private readonly Regex regularExpression = new Regex(Pattern); 19 | private readonly ThreadLocal requestedFileName = new ThreadLocal(() => string.Empty); 20 | private readonly string configuredBasePath; 21 | private readonly string configuredDefaultPages; 22 | 23 | private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 24 | 25 | public FileHandler(string name, string defaultPages, string basePath) 26 | : base(name) 27 | { 28 | this.configuredBasePath = basePath; 29 | this.configuredDefaultPages = defaultPages; 30 | } 31 | 32 | 33 | public override bool ShouldHandle(HttpListenerRequest request) 34 | { 35 | if (request.RawUrl == "/") 36 | { 37 | if (!string.IsNullOrEmpty(configuredDefaultPages)) 38 | { 39 | var defaultPageList = configuredDefaultPages.Split(';').Select(p => p.Trim()); 40 | foreach (var defaultPage in defaultPageList) 41 | { 42 | var fullName = Path.Combine(this.configuredBasePath, defaultPage); 43 | if (File.Exists(fullName)) 44 | { 45 | this.requestedFileName.Value = defaultPage; 46 | return true; 47 | } 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | var match = this.regularExpression.Match(request.RawUrl.Trim('\\', '/', '?')); 54 | if (match.Success) 55 | { 56 | this.requestedFileName.Value = match.Groups["fileName"].Value; 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | public override HandlerProcessResult Process(HttpListenerRequest request) 63 | { 64 | try 65 | { 66 | var fileNameRequested = Path.Combine(this.configuredBasePath, this.requestedFileName.Value.Replace("/", Path.DirectorySeparatorChar.ToString())); 67 | log.DebugFormat("File requested: {0}", fileNameRequested); 68 | if (!File.Exists(fileNameRequested)) 69 | { 70 | return HandlerProcessResult.Text(HttpStatusCode.NotFound, string.Format("Requested file \"{0}\" doesn't exist.", fileNameRequested)); 71 | } 72 | else 73 | { 74 | var fileBytes = File.ReadAllBytes(fileNameRequested); 75 | var contentType = Utils.GetMimeType(Path.GetExtension(fileNameRequested)); 76 | return HandlerProcessResult.File(HttpStatusCode.OK, contentType, fileBytes); 77 | } 78 | } 79 | catch(Exception ex) 80 | { 81 | log.Error("Error occurred when processing the request.", ex); 82 | return HandlerProcessResult.Exception(HttpStatusCode.InternalServerError, ex); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Raspkate/IRaspkateHandler.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------------------------------- 2 | // 3 | // jSL 4 | // j2S0Z0S7, ,@BE 5 | // ;@@@@B@B@B@ @@@. @B@ 6 | // O@@i B@BL rv7 i: .rujr. .: i7r. B@B i7: .iLr .:, ,LB@@.i ,LJL: 7 | // @B@ :@B@ ,@@B@B@M@B@ :@@@B@@@ @B@Z@B@@@G r@BY P@@@, :@B@B@BOB@E 0@B@B@B@i PB@@@B@@5 8 | // rB@BN0NB@B0 :B@B, :@@@. @B@ iB@@@. @B@. @@@ .B@Bi ;@B@. rB@B @@@ @B@ B@B 9 | // B@B@@@B@B B@B B@B @@BB7 O@BU B@B. B@BOB@: @@@ @B@ :B@2 @B@OuX@B@@i 10 | // @B@ 1B@M r@BX 1@Bu :0B@B@ @B@ @@@ L@Br2@BL u@@J ZB@7 B@B ,B@MYP0j: 11 | //YB@8 @B@. U@@X G@B@ @@B rB@M @B@. @B@ B@@J P@Bu @B@B @B@ ;@@0 12 | //@@Bi B@@@ @@@@@@@B@B @@@qN@@B7 B@B@B@B@B@: :B@B @@BL ,B@B@B@B@B@ .@@@@B1 B@B@ZO@@B. 13 | //0k2 iFPY 5O@k. uk: ,XB@BZ; @B@ LB@Pi :0k: ,SNj .1MBF 1X. :5MMq iF@@BBS: 14 | // uB@J 15 | // M@B 16 | // 17 | // Raspkate Service by daxnet, 2016 18 | // https://github.com/daxnet/raspkate 19 | // Licensed under GPL v2.0 20 | // ------------------------------------------------------------------------------------------------------- 21 | 22 | using System.Net; 23 | 24 | namespace Raspkate 25 | { 26 | /// 27 | /// Represents that the implemented classes are Raspkate HTTP handlers. 28 | /// 29 | public interface IRaspkateHandler 30 | { 31 | /// 32 | /// Gets the name of the handler. 33 | /// 34 | /// 35 | /// The name. 36 | /// 37 | string Name { get; } 38 | /// 39 | /// Returns a value which indicates whether the current handler 40 | /// can handle the given HTTP request. 41 | /// 42 | /// The request object to be validated. 43 | /// True if current handler can handle the given request, otherwise, False. 44 | bool ShouldHandle(HttpListenerRequest request); 45 | 46 | /// 47 | /// Processes the given request and returns the response. 48 | /// 49 | /// The request to be processed by current handler. 50 | /// The response which contains the returned data. 51 | HandlerProcessResult Process(HttpListenerRequest request); 52 | 53 | void OnRegistering(); 54 | void OnUnregistered(); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Raspkate/IRaspkateModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate 8 | { 9 | public interface IRaspkateModule 10 | { 11 | IEnumerable RegisteredHandlers { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Raspkate/IRaspkateServer.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------------------------------- 2 | // 3 | // jSL 4 | // j2S0Z0S7, ,@BE 5 | // ;@@@@B@B@B@ @@@. @B@ 6 | // O@@i B@BL rv7 i: .rujr. .: i7r. B@B i7: .iLr .:, ,LB@@.i ,LJL: 7 | // @B@ :@B@ ,@@B@B@M@B@ :@@@B@@@ @B@Z@B@@@G r@BY P@@@, :@B@B@BOB@E 0@B@B@B@i PB@@@B@@5 8 | // rB@BN0NB@B0 :B@B, :@@@. @B@ iB@@@. @B@. @@@ .B@Bi ;@B@. rB@B @@@ @B@ B@B 9 | // B@B@@@B@B B@B B@B @@BB7 O@BU B@B. B@BOB@: @@@ @B@ :B@2 @B@OuX@B@@i 10 | // @B@ 1B@M r@BX 1@Bu :0B@B@ @B@ @@@ L@Br2@BL u@@J ZB@7 B@B ,B@MYP0j: 11 | //YB@8 @B@. U@@X G@B@ @@B rB@M @B@. @B@ B@@J P@Bu @B@B @B@ ;@@0 12 | //@@Bi B@@@ @@@@@@@B@B @@@qN@@B7 B@B@B@B@B@: :B@B @@BL ,B@B@B@B@B@ .@@@@B1 B@B@ZO@@B. 13 | //0k2 iFPY 5O@k. uk: ,XB@BZ; @B@ LB@Pi :0k: ,SNj .1MBF 1X. :5MMq iF@@BBS: 14 | // uB@J 15 | // M@B 16 | // 17 | // Raspkate Service by daxnet, 2016 18 | // https://github.com/daxnet/raspkate 19 | // Licensed under GPL v2.0 20 | // ------------------------------------------------------------------------------------------------------- 21 | 22 | using Raspkate.Config; 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace Raspkate 30 | { 31 | public interface IRaspkateServer 32 | { 33 | RaspkateConfiguration Configuration { get; } 34 | IEnumerable Handlers { get; } 35 | void Start(); 36 | void Stop(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Raspkate/Modules/ModuleContext.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Raspkate.Modules 10 | { 11 | public sealed class ModuleContext 12 | { 13 | private const string SettingsFileName = "settings.json"; 14 | private readonly Lazy>> settings; 15 | 16 | internal ModuleContext(string rootFolder, string moduleFolder) 17 | { 18 | this.RootFolder = rootFolder; 19 | this.ModuleFolder = moduleFolder; 20 | settings = new Lazy>>(() => 21 | { 22 | var result = new Dictionary(); 23 | if (File.Exists(SettingsFile)) 24 | { 25 | dynamic configuration = JsonConvert.DeserializeObject(File.ReadAllText(SettingsFile)); 26 | foreach (dynamic setting in configuration.settings) 27 | { 28 | result.Add((string)setting.key, (string)setting.value); 29 | } 30 | } 31 | return result; 32 | }); 33 | } 34 | 35 | public string RootFolder { get; internal set; } 36 | 37 | public string ModuleFolder { get; internal set; } 38 | 39 | public string SettingsFile 40 | { 41 | get { return Path.Combine(this.ModuleFolder, SettingsFileName); } 42 | } 43 | 44 | public IEnumerable> Settings 45 | { 46 | get 47 | { 48 | return settings.Value; 49 | } 50 | } 51 | 52 | public string ReadSetting(string key) 53 | { 54 | var setting = this.Settings.FirstOrDefault(x => x.Key == key); 55 | return setting.Value; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Raspkate/Modules/RaspkateModule.cs: -------------------------------------------------------------------------------- 1 | using Raspkate.Config; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Raspkate.Modules 11 | { 12 | public abstract class RaspkateModule : IRaspkateModule 13 | { 14 | private readonly ModuleContext context; 15 | private readonly Lazy> registeredHandlers; 16 | 17 | protected RaspkateModule(ModuleContext context) 18 | { 19 | this.context = context; 20 | this.registeredHandlers = new Lazy>(CreateHandlers); 21 | this.RegisterExternalDependencies(); 22 | } 23 | 24 | protected ModuleContext Context { get { return this.context; } } 25 | 26 | protected abstract IEnumerable CreateHandlers(); 27 | 28 | protected virtual void RegisterExternalDependencies() 29 | { 30 | var externalDependencies = new Dictionary(); 31 | foreach (var file in Directory.EnumerateFiles(Context.ModuleFolder, "*.dll", SearchOption.TopDirectoryOnly)) 32 | { 33 | try 34 | { 35 | var dependency = Assembly.LoadFrom(file); 36 | if (dependency.FullName != Assembly.GetExecutingAssembly().FullName) 37 | { 38 | externalDependencies.Add(dependency.FullName, dependency); 39 | } 40 | } 41 | catch { } 42 | } 43 | 44 | AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => 45 | { 46 | Assembly resolution; 47 | externalDependencies.TryGetValue(e.Name, out resolution); 48 | return resolution; 49 | }; 50 | } 51 | 52 | public IEnumerable RegisteredHandlers 53 | { 54 | get { return registeredHandlers.Value; } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Raspkate/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Raspkate.Common")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Raspkate.Common")] 13 | [assembly: AssemblyCopyright("Copyright © 2016 by daxnet.")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0a9a4b24-675c-4054-94fd-4160d93d8380")] 24 | 25 | [assembly: log4net.Config.XmlConfigurator(Watch=true)] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | [assembly: InternalsVisibleTo("Raspkate.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001005f2194c5fe8df0" + 40 | "05c981376c6e06c056885acb7c5036b730e93c4724509c45556ac7895282c06e8b21ad4a19296e" + 41 | "6ac90310c49a97a63017de0a068f52f8ea23bc68f4f9baceebf48205d3c64d487ce378a3d9077b" + 42 | "e876e2ce33e0ba91310ec927c63e3cd671de7f290b85050f694745fa7258e09ff8fa036eb78092" + 43 | "d94ed7b2")] -------------------------------------------------------------------------------- /src/Raspkate/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Raspkate.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Raspkate.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to ** 65 | /// ****** ** 66 | /// ** *** ** ** 67 | /// ** ** ******* ***** ******* ** *** ******* ***** ****** 68 | /// ****** *** ** *** *** ** ** ** ** ** ** ** ** 69 | /// ** ** ** ** **** ** ** ***** *** * * ****** 70 | /// ** ** ** ** *** ** *** ** ** ** ** ** ** 71 | /// ** ** *** [rest of string was truncated]";. 72 | /// 73 | internal static string Logo { 74 | get { 75 | return ResourceManager.GetString("Logo", resourceCulture); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Raspkate/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | ** 122 | ****** ** 123 | ** *** ** ** 124 | ** ** ******* ***** ******* ** *** ******* ***** ****** 125 | ****** *** ** *** *** ** ** ** ** ** ** ** ** 126 | ** ** ** ** **** ** ** ***** *** * * ****** 127 | ** ** ** ** *** ** *** ** ** ** ** ** ** 128 | ** ** ******* ****** ******** *** *** ******* **** ******* 129 | ** 130 | ** 131 | 132 | 133 | -------------------------------------------------------------------------------- /src/Raspkate/Raspkate.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {38BB78EF-CFA0-457A-B216-5B3AFF7C5520} 8 | Library 9 | Properties 10 | Raspkate 11 | Raspkate 12 | v4.5.2 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\bin\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | true 36 | 37 | 38 | Raspkate.snk 39 | 40 | 41 | 42 | False 43 | ..\..\lib\log4net.dll 44 | 45 | 46 | False 47 | ..\..\lib\Newtonsoft.Json.dll 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | True 62 | True 63 | RaspkateConfig.csd 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | True 90 | True 91 | Resources.resx 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | CsdFileGenerator 105 | RaspkateConfig.csd.cs 106 | 107 | 108 | RaspkateConfig.csd 109 | 110 | 111 | RaspkateConfig.csd 112 | 113 | 114 | RaspkateConfig.csd 115 | Designer 116 | 117 | 118 | 119 | 120 | 121 | ResXFileCodeGenerator 122 | Resources.Designer.cs 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 134 | 135 | 136 | 137 | 144 | -------------------------------------------------------------------------------- /src/Raspkate/Raspkate.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daxnet/raspkate/c4c1ede77a99c33976246d055ba9e65dfb6b4f73/src/Raspkate/Raspkate.snk -------------------------------------------------------------------------------- /src/Raspkate/RaspkateException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Raspkate 8 | { 9 | public class RaspkateException : Exception 10 | { 11 | public RaspkateException() 12 | { } 13 | 14 | public RaspkateException(string message) 15 | : base(message) 16 | { } 17 | 18 | public RaspkateException(string format, params string[] args) 19 | : base(string.Format(format, args)) 20 | { } 21 | 22 | public RaspkateException(string message, Exception innerException) 23 | : base(message, innerException) 24 | { } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Raspkate/RaspkateHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Raspkate 7 | { 8 | public abstract class RaspkateHandler : IRaspkateHandler 9 | { 10 | private readonly string name; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The instance on which the module 16 | /// is registered and executed. 17 | protected RaspkateHandler(string name) 18 | { 19 | this.name = name; 20 | } 21 | 22 | /// 23 | /// Gets the name of the handler. 24 | /// 25 | /// 26 | /// The name. 27 | /// 28 | public string Name 29 | { 30 | get { return this.name; } 31 | } 32 | 33 | public virtual void OnRegistering() { } 34 | 35 | public virtual void OnUnregistered() { } 36 | 37 | /// 38 | /// Checks if the incoming request can be processed by the current module. 39 | /// 40 | /// The incoming request. 41 | /// True if the current module can process the incoming request, otherwise, False. 42 | public abstract bool ShouldHandle(HttpListenerRequest request); 43 | 44 | /// 45 | /// Processes the given request and populate the response with the processing result. 46 | /// 47 | /// The request which should be processed. 48 | /// The response to which the processing result is populated. 49 | public abstract HandlerProcessResult Process(HttpListenerRequest request); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Raspkate/RaspkateServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading; 7 | using Newtonsoft.Json; 8 | using Raspkate.Config; 9 | using System.Reflection; 10 | using Raspkate.Properties; 11 | using System.IO; 12 | using System.Xml.Serialization; 13 | using Raspkate.Modules; 14 | 15 | namespace Raspkate 16 | { 17 | public class RaspkateServer : IRaspkateServer 18 | { 19 | private Thread thread; 20 | private readonly RaspkateConfiguration configuration; 21 | private readonly HttpListener listener = new HttpListener(); 22 | private volatile bool cancelled; 23 | private volatile bool prefixesRegistered; 24 | private readonly ManualResetEvent stopEvent = new ManualResetEvent(false); 25 | private readonly List handlers = new List(); 26 | 27 | private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 28 | 29 | public RaspkateServer(RaspkateConfiguration configuration) 30 | { 31 | this.configuration = configuration; 32 | } 33 | 34 | public IEnumerable Handlers 35 | { 36 | get { return this.handlers; } 37 | } 38 | 39 | public RaspkateConfiguration Configuration 40 | { 41 | get { return this.configuration; } 42 | } 43 | 44 | public void Start() 45 | { 46 | log.Info(Resources.Logo); 47 | log.Info("Raspkate - A small and lightweight Web Server"); 48 | log.InfoFormat("[ Version: {0} ]", Version); 49 | log.DebugFormat("Starting Raspkate service with the configuration:{0}{1}", Environment.NewLine, this.configuration); 50 | this.RegisterPrefixes(new[] { configuration.Prefix }); 51 | this.RegisterHandlers(configuration); 52 | log.Debug("Starting HttpListener based on configuration."); 53 | this.listener.Start(); 54 | log.Debug("HttpListener started successfully."); 55 | log.Debug("Starting service thread."); 56 | this.thread = new Thread(this.ExecuteThread); 57 | this.thread.Start(this.listener); 58 | log.DebugFormat("Service thread started successfully, ManagedThreadId={0}", this.thread.ManagedThreadId); 59 | log.Info("Service started."); 60 | } 61 | 62 | public void Stop() 63 | { 64 | log.Debug("Sending the STOP signal."); 65 | this.cancelled = true; 66 | this.stopEvent.Set(); 67 | log.Debug("Waiting for service thread."); 68 | this.thread.Join(); 69 | log.Debug("Service thread stopped successfully."); 70 | log.Debug("Stopping HttpListener."); 71 | this.listener.Stop(); 72 | log.Debug("HttpListener stopped successfully."); 73 | this.UnregisterHandlers(); 74 | log.Info("Raspkate service stopped successfully."); 75 | } 76 | 77 | private static Version Version 78 | { 79 | get 80 | { 81 | return Assembly.GetExecutingAssembly().GetName().Version; 82 | } 83 | } 84 | 85 | private void RegisterHandlers(RaspkateConfiguration config) 86 | { 87 | if (config.Modules != null && config.Modules.Count > 0) 88 | { 89 | var entryAssemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 90 | foreach(ModuleElement moduleElement in config.Modules) 91 | { 92 | var searchPath = moduleElement.IsRelative ? 93 | Path.Combine(entryAssemblyPath, moduleElement.Path) : 94 | moduleElement.Path; 95 | if (Directory.Exists(searchPath)) 96 | { 97 | foreach (var moduleAssemblyFile in Directory.EnumerateFiles(searchPath, "*.dll", SearchOption.AllDirectories)) 98 | { 99 | try 100 | { 101 | var moduleAssembly = Assembly.LoadFile(moduleAssemblyFile); 102 | if (moduleAssembly != null) 103 | { 104 | var moduleTypes = from type in moduleAssembly.GetTypes() 105 | where typeof(IRaspkateModule).IsAssignableFrom(type) 106 | select type; 107 | foreach(var moduleType in moduleTypes) 108 | { 109 | var context = new ModuleContext(entryAssemblyPath, Path.GetDirectoryName(moduleAssemblyFile)); 110 | var module = (IRaspkateModule)Activator.CreateInstance(moduleType, context); 111 | if (module != null && module.RegisteredHandlers != null) 112 | { 113 | foreach (var handler in module.RegisteredHandlers) 114 | { 115 | handler.OnRegistering(); 116 | this.handlers.Add(handler); 117 | log.InfoFormat("Handler \"{0}\" registered successfully.", handler.Name); 118 | } 119 | } 120 | else 121 | { 122 | log.WarnFormat("No registered handlers being provided by type \"{0}\", skipping...", moduleType); 123 | } 124 | } 125 | } 126 | } 127 | catch (Exception ex) 128 | { 129 | log.Debug(string.Format("Unable to load assembly from file \"{0}\".", moduleAssemblyFile), ex); 130 | } 131 | } 132 | } 133 | else 134 | { 135 | log.WarnFormat("Specified module path \"{0}\" does not exist.", searchPath); 136 | } 137 | } 138 | } 139 | } 140 | 141 | private void UnregisterHandlers() 142 | { 143 | handlers.ForEach(h => h.OnUnregistered()); 144 | } 145 | 146 | private void ExecuteThread(object arg) 147 | { 148 | var httpListener = (HttpListener)arg; 149 | while (!this.cancelled && httpListener.IsListening) 150 | { 151 | var asyncResult = httpListener.BeginGetContext(this.OnGetContext, httpListener); 152 | if (WaitHandle.WaitAny(new[] { this.stopEvent, asyncResult.AsyncWaitHandle }) == 0) 153 | { 154 | break; 155 | } 156 | } 157 | } 158 | 159 | private void OnGetContext(IAsyncResult result) 160 | { 161 | if (this.thread.IsAlive) 162 | { 163 | var httpListener = (HttpListener)result.AsyncState; 164 | httpListener.BeginGetContext(new AsyncCallback(OnGetContext), httpListener); 165 | var context = httpListener.EndGetContext(result); 166 | try 167 | { 168 | this.ProcessRequest(context); 169 | } 170 | catch(HttpListenerException ex) 171 | { 172 | log.DebugFormat("HttpListener raised exception. Written to log for debugging reference.", ex); 173 | } 174 | catch(Exception ex) 175 | { 176 | log.Error("Exception occurred.", ex); 177 | } 178 | finally 179 | { 180 | try 181 | { 182 | context.Response.OutputStream.Flush(); 183 | context.Response.OutputStream.Close(); 184 | context.Response.Close(); 185 | } 186 | catch (Exception ex) 187 | { 188 | log.Error("Cannot flush and close the response stream.", ex); 189 | } 190 | finally 191 | { } 192 | } 193 | } 194 | } 195 | 196 | private void ProcessRequest(HttpListenerContext context) 197 | { 198 | var incorrectResults = new List>(); 199 | foreach (var handler in this.handlers) 200 | { 201 | try 202 | { 203 | if (handler.ShouldHandle(context.Request)) 204 | { 205 | var result = handler.Process(context.Request); 206 | if (result.StatusCode == HttpStatusCode.OK) 207 | { 208 | context.Response.WriteResponse(result); 209 | return; 210 | } 211 | else 212 | { 213 | incorrectResults.Add(new Tuple(handler, result)); 214 | } 215 | } 216 | else 217 | { 218 | log.DebugFormat("Handler \"{0}\" cannot handle the request with URL \"{1}\", skipped.", handler, context.Request.Url); 219 | } 220 | } 221 | catch (Exception ex) 222 | { 223 | log.Warn(string.Format("Failed to check whether the current handler (Handler: \"{0}\") can handle the given request, skipping...", handler), ex); 224 | } 225 | } 226 | 227 | if (incorrectResults.Count == 0) 228 | { 229 | context.Response.WriteResponse(HandlerProcessResult.Text(HttpStatusCode.BadRequest, "Invalid request.")); 230 | } 231 | else if (incorrectResults.Count == 1) 232 | { 233 | context.Response.WriteResponse(incorrectResults[0].Item2); 234 | } 235 | else 236 | { 237 | var groupings = incorrectResults.GroupBy(x => x.Item2.StatusCode); 238 | if (groupings.Count() == 1) 239 | { 240 | context.Response.WriteResponse(groupings.First().Key, incorrectResults); 241 | } 242 | else 243 | { 244 | context.Response.WriteResponse(HttpStatusCode.InternalServerError, incorrectResults); 245 | } 246 | } 247 | } 248 | 249 | private void RegisterPrefixes(string[] prefixes) 250 | { 251 | if (!this.prefixesRegistered) 252 | { 253 | foreach (var prefix in prefixes) 254 | { 255 | this.listener.Prefixes.Add(prefix); 256 | } 257 | this.prefixesRegistered = true; 258 | } 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/build.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | IF /I "%1"=="Debug" GOTO BuildDebug 3 | IF /I "%1"=="All" GOTO BuildAll 4 | IF /I "%1"=="Minimal" GOTO BuildMinimal 5 | 6 | :ER 7 | ECHO. 8 | ECHO Raspkate Command-Line Build Tool v1.0 9 | ECHO. 10 | ECHO Usage: 11 | ECHO build.bat Debug 12 | ECHO Builds the Raspkate with Debug configuration. 13 | ECHO. 14 | ECHO build.bat Release 15 | ECHO Builds the Raspkate with Release configuration. 16 | ECHO. 17 | GOTO End 18 | 19 | :BuildDebug 20 | msbuild /p:Configuration="Debug";TargetFrameworkVersion="v4.5.2" Raspkate.sln 21 | GOTO End 22 | 23 | :BuildAll 24 | msbuild /p:Configuration="All";TargetFrameworkVersion="v4.5.2" Raspkate.sln 25 | GOTO End 26 | 27 | :BuildMinimal 28 | msbuild /p:Configuration="Minimal";TargetFrameworkVersion="v4.5.2" Raspkate.sln 29 | GOTO End 30 | 31 | :End 32 | @ECHO ON 33 | -------------------------------------------------------------------------------- /src/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | PARAM='' 3 | if [ "$1" == 'Debug' ] 4 | then 5 | PARAM='/property:Configuration=Debug;TargetFrameworkVersion=v4.5 Raspkate.sln' 6 | elif [ "$1" == 'All' ] 7 | then 8 | PARAM='/property:Configuration=All;TargetFrameworkVersion=v4.5 Raspkate.sln' 9 | elif [ "$1" == 'Minimal' ] 10 | then 11 | PARAM='/property:Configuration=Minimal;TargetFrameworkVersion=v4.5 Raspkate.sln' 12 | else 13 | printf "\n" 14 | printf "Raspkate Command-Line Build Tool v1.0\n\n" 15 | printf "Usage:\n" 16 | printf " build.sh Debug\n" 17 | printf " Builds the Raspkate with Debug configuration.\n\n" 18 | printf " build.sh Release\n" 19 | printf " Builds the Raspkate with Release configuration.\n\n" 20 | exit $? 21 | fi 22 | 23 | xbuild $PARAM 24 | --------------------------------------------------------------------------------