waxx 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/README.md +75 -79
- data/lib/waxx/app.rb +9 -3
- data/lib/waxx/console.rb +15 -11
- data/lib/waxx/database.rb +9 -1
- data/lib/waxx/encrypt.rb +2 -2
- data/lib/waxx/http.rb +16 -10
- data/lib/waxx/mongodb.rb +9 -0
- data/lib/waxx/patch.rb +27 -2
- data/lib/waxx/pdf.rb +4 -4
- data/lib/waxx/pg.rb +19 -7
- data/lib/waxx/res.rb +14 -2
- data/lib/waxx/server.rb +37 -16
- data/lib/waxx/version.rb +1 -1
- data/lib/waxx/view.rb +2 -2
- data/lib/waxx/waxx.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +25 -22
- metadata.gz.sig +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0f46260fb9e41a49af9eb045a81a88ef270e01100626d8b4458f8e6b9c633ebc
|
|
4
|
+
data.tar.gz: 5e0071cbe8095d8c084ca2089a4a69c8d46f397620f493ebf80f43f9e5b96192
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd026b73c6a231fb17d4edf1aa03810bec7760356b21697c352b1cce723efa2120f779ad1ac049c3ab364d5a273c37384b77f9bd03676b6d845636c1228ef533
|
|
7
|
+
data.tar.gz: 64b91a88da24468dc8735bf2b4c79686962a726ae71e2e06abc6c4e64dff3db4492f02250394e9670742857368ed7c22fcda0bf3e253de8a3e6600f3d1fc7e01
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/README.md
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# Waxx - Web Application X(x)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
**NOTICE: Waxx does not run on Windows yet. Working on it. Stay tuned.**
|
|
6
|
-
|
|
7
|
-
The Waxx Framerwork is a high perfomance, functional-inspired (but not truly functional), web application development environment written in Ruby and inspired by Go and Haskel.
|
|
3
|
+
The Waxx Framework is a high perfomance, functional-inspired (but not truly functional), web application development environment written in Ruby and inspired by Go and Haskel.
|
|
8
4
|
|
|
9
5
|
## Goals
|
|
10
6
|
|
|
@@ -16,11 +12,11 @@ The Waxx Framerwork is a high perfomance, functional-inspired (but not truly fun
|
|
|
16
12
|
|
|
17
13
|
## Target Users
|
|
18
14
|
|
|
19
|
-
The Waxx Framework was developed to build CRUD applications and REST and RPC services. It scales very well on multi-core machines and is
|
|
15
|
+
The Waxx Framework was developed to build CRUD applications and REST and RPC services. It scales very well on multi-core machines and is suitable for very large deployments.
|
|
20
16
|
|
|
21
17
|
## Who's Behind This
|
|
22
18
|
|
|
23
|
-
Waxx was developed by Dan Fitzpatrick at [ePark Labs](https://www.eparklabs.com/).
|
|
19
|
+
Waxx was developed by Dan Fitzpatrick at [ePark Labs](https://www.eparklabs.com/).
|
|
24
20
|
|
|
25
21
|
## Hello World
|
|
26
22
|
|
|
@@ -63,7 +59,7 @@ waxx on
|
|
|
63
59
|
|
|
64
60
|
The Waxx gem is cryptographically signed to be sure the gem you install hasn't been tampered with.
|
|
65
61
|
Because of this you need to add the public key to your list of trusted gem certs.
|
|
66
|
-
Follow
|
|
62
|
+
Follow these direction. (You only need step one the first time you install the gem.)
|
|
67
63
|
|
|
68
64
|
```bash
|
|
69
65
|
sudo gem cert --add <(curl -s https://www.waxx.io/waxx-gem-public-key.pem)
|
|
@@ -79,23 +75,23 @@ Then run `waxx buff` (waxx off && waxx on) or if you prefer `waxx restart`
|
|
|
79
75
|
See [Install Waxx](https://www.waxx.io/doc/install) for complete details.
|
|
80
76
|
|
|
81
77
|
### High Performance
|
|
82
|
-
Waxx is multi-threaded queue-based system.
|
|
83
|
-
You specify the number of threads in the config file.
|
|
84
|
-
Each thread is prespawned and each thread makes it's own database connection.
|
|
85
|
-
Requests are received and put into a FIFO request queue.
|
|
86
|
-
The threads work through the queue.
|
|
87
|
-
Each request, including session management, a database query, access control, and rendering in HTML or JSON is approximately 1-2ms (on a modern Xeon server).
|
|
88
|
-
With additional libraries, Waxx also easily generates XML, XLSX, CSV, PDF, etc.
|
|
89
|
-
|
|
90
|
-
### Easy to Grok
|
|
91
|
-
Waxx has no Classes.
|
|
92
|
-
It is Module-based and the Modules have methods (functions).
|
|
93
|
-
Each method within a Module is given parameters and the method runs in isolation.
|
|
94
|
-
There are no instance variables and no global variables.
|
|
95
|
-
Consequently, it is very easy to understand what any method does and it is very easy to test methods.
|
|
96
|
-
You can call any method in the whole system from the console using `waxx console`.
|
|
97
|
-
Passing in the same variables to a function will always return the same result.
|
|
98
|
-
Waxx does have `x.res.out` variable, which is appended to with `x << "text"`, that is passed into each method and any method can append to the response body or set response headers.
|
|
78
|
+
Waxx is multi-threaded queue-based system.
|
|
79
|
+
You specify the number of threads in the config file.
|
|
80
|
+
Each thread is prespawned and each thread makes it's own database connection.
|
|
81
|
+
Requests are received and put into a FIFO request queue.
|
|
82
|
+
The threads work through the queue.
|
|
83
|
+
Each request, including session management, a database query, access control, and rendering in HTML or JSON is approximately 1-2ms (on a modern Xeon server).
|
|
84
|
+
With additional libraries, Waxx also easily generates XML, XLSX, CSV, PDF, etc.
|
|
85
|
+
|
|
86
|
+
### Easy to Grok
|
|
87
|
+
Waxx has no Classes.
|
|
88
|
+
It is Module-based and the Modules have methods (functions).
|
|
89
|
+
Each method within a Module is given parameters and the method runs in isolation.
|
|
90
|
+
There are no instance variables and no global variables.
|
|
91
|
+
Consequently, it is very easy to understand what any method does and it is very easy to test methods.
|
|
92
|
+
You can call any method in the whole system from the console using `waxx console`.
|
|
93
|
+
Passing in the same variables to a function will always return the same result.
|
|
94
|
+
Waxx does have `x.res.out` variable, which is appended to with `x << "text"`, that is passed into each method and any method can append to the response body or set response headers.
|
|
99
95
|
So it is not truly functional because this is considered a side effect.
|
|
100
96
|
My opinion is that when you are building a response, then copying the response on every method is a waste of resources.
|
|
101
97
|
So it does have this side effect by design.
|
|
@@ -103,7 +99,7 @@ So it does have this side effect by design.
|
|
|
103
99
|
#### Waxx Terminology
|
|
104
100
|
|
|
105
101
|
- Object: A database table or database object or a container for some specific functionality
|
|
106
|
-
- Object `has` fields (an array of Hashes). A field is both a database field/column/attribute and a UI control (for HTML apps)
|
|
102
|
+
- Object `has` fields (an array of Hashes). A field is both a database field/column/attribute and a UI control (for HTML apps)
|
|
107
103
|
- Field `is` (represents) a single object (INNER JOIN) or many related objects (LEFT JOIN)
|
|
108
104
|
- Object `runs` a URL path - business logic (normally get from or post to a view)
|
|
109
105
|
- View: Like a DB view -- fields from one or more tables/objects
|
|
@@ -146,26 +142,26 @@ Waxx was built with code maintainablity in mind. The following principles help i
|
|
|
146
142
|
1. Simple to know where the code is located for any URI. A request to /person/list will start in the `app/person/person.rb` file and normally use the view defined in the file `app/person/list.rb`
|
|
147
143
|
2. Fields are defined upfront. The fields you want to use in your app are defined in the Object file `app/person/person.rb`
|
|
148
144
|
3. Field have attributes that make a lot of UI development simple (optional). has(email: {label: "Email Address" ...})`
|
|
149
|
-
4. Views allow you to see exactly what is on an interface and all the business logic. Only the fields on a view can be updated so it is impossible to taint the database by passing in extra parameters.
|
|
145
|
+
4. Views allow you to see exactly what is on an interface and all the business logic. Only the fields on a view can be updated so it is impossible to taint the database by passing in extra parameters.
|
|
150
146
|
5. Most rendering is automatic unless you want to do special stuff. You can use pure Ruby functions or your favorite template engine. The View file `app/person/list.rb` contains all of the fields, joined tables, and layout for a view.
|
|
151
147
|
6. Full visibility into the external API and each endpoint's access control allows to immediate auditing of who can see and do what.
|
|
152
148
|
|
|
153
149
|
There are no routes.
|
|
154
|
-
All paths are `/:app/:act/:arg1/:arg2/...`.
|
|
155
|
-
The URL maps to an App and runs the act (method).
|
|
156
|
-
For example: `example.com/person/list` will execute the `list` method in the `App::Person` module.
|
|
157
|
-
This method is defined in `app/person/person.rb`.
|
|
158
|
-
Another example: A request to `/website_page/content/3` will execute the `content` method in the `App::WebsitePage` app and pass in `3` as the first parameter after 'x'.
|
|
159
|
-
There is a default app and a default method in each app.
|
|
150
|
+
All paths are `/:app/:act/:arg1/:arg2/...`.
|
|
151
|
+
The URL maps to an App and runs the act (method).
|
|
152
|
+
For example: `example.com/person/list` will execute the `list` method in the `App::Person` module.
|
|
153
|
+
This method is defined in `app/person/person.rb`.
|
|
154
|
+
Another example: A request to `/website_page/content/3` will execute the `content` method in the `App::WebsitePage` app and pass in `3` as the first parameter after 'x'.
|
|
155
|
+
There is a default app and a default method in each app.
|
|
160
156
|
So a request to `example.com/` will show the home page if the default app is `website` and the default method in website is `home`.
|
|
161
157
|
|
|
162
158
|
|
|
163
159
|
### File Structure
|
|
164
|
-
Waxx places each module in it's own directory. This includes the Object, Runner, Views, Layouts, and Tests.
|
|
165
|
-
I normally place my app-specific javascript and css in this same folder as well.
|
|
166
|
-
In this way, all of the functionality and features of a specific App or Module are fully self-contained.
|
|
167
|
-
However, you can optionally put your files anywhere and require them in your code.
|
|
168
|
-
So if you like all the objects to be in one folder you can do that.
|
|
160
|
+
Waxx places each module in it's own directory. This includes the Object, Runner, Views, Layouts, and Tests.
|
|
161
|
+
I normally place my app-specific javascript and css in this same folder as well.
|
|
162
|
+
In this way, all of the functionality and features of a specific App or Module are fully self-contained.
|
|
163
|
+
However, you can optionally put your files anywhere and require them in your code.
|
|
164
|
+
So if you like all the objects to be in one folder you can do that.
|
|
169
165
|
If you work with a large team where backend and frontend people do not overlap, then maybe that will work for you.
|
|
170
166
|
|
|
171
167
|
This is a normal structure:
|
|
@@ -231,7 +227,7 @@ This is a normal structure:
|
|
|
231
227
|
| `-- deploy # The script to deploy to stage (run on the production server(s))
|
|
232
228
|
|-- private # A folder for private files (served by the file app if included)
|
|
233
229
|
`-- public # The public folder (Web server should have this as the root)
|
|
234
|
-
|
|
230
|
+
|
|
235
231
|
```
|
|
236
232
|
|
|
237
233
|
The Waxx::Object has two purposes:
|
|
@@ -297,7 +293,7 @@ require_relative 'list' # The List View is defined here
|
|
|
297
293
|
require_relative 'record' # The Record View is defined here
|
|
298
294
|
```
|
|
299
295
|
|
|
300
|
-
A view is like a database view (not like a Rails view). The view specifies what tables/objects and fields/properties are going to be displayed and potentially edited. The Html layout module is like a Rails view. Other layouts include: Json, Csv, Pdf, Xlsx.
|
|
296
|
+
A view is like a database view (not like a Rails view). The view specifies what tables/objects and fields/properties are going to be displayed and potentially edited. The Html layout module is like a Rails view. Other layouts include: Json, Csv, Pdf, Xlsx.
|
|
301
297
|
|
|
302
298
|
**app/person/list.rb** *(This is the view that lists the users)*
|
|
303
299
|
|
|
@@ -305,7 +301,7 @@ A view is like a database view (not like a Rails view). The view specifies what
|
|
|
305
301
|
module App::Person::List
|
|
306
302
|
extend Waxx::View
|
|
307
303
|
extend self
|
|
308
|
-
|
|
304
|
+
|
|
309
305
|
has(
|
|
310
306
|
:id,
|
|
311
307
|
:first_name,
|
|
@@ -313,28 +309,28 @@ module App::Person::List
|
|
|
313
309
|
:email
|
|
314
310
|
# This view does not include the bio field
|
|
315
311
|
)
|
|
316
|
-
|
|
312
|
+
|
|
317
313
|
module Html
|
|
318
314
|
extend Waxx::Html
|
|
319
315
|
extend self
|
|
320
|
-
|
|
316
|
+
|
|
321
317
|
def get(x, data, message={})
|
|
322
|
-
# This method appends to x and includes your site layout and nav.
|
|
318
|
+
# This method appends to x and includes your site layout and nav.
|
|
323
319
|
# The content attribute is what goes in the content area of the page.
|
|
324
320
|
App::Html.page(x,
|
|
325
321
|
title: "People",
|
|
326
322
|
content: content(x, data)
|
|
327
323
|
)
|
|
328
324
|
end
|
|
329
|
-
|
|
325
|
+
|
|
330
326
|
def content(x, data)
|
|
331
327
|
# You put your HTML output here using:
|
|
332
328
|
%(<p>HTHL or a template engine</p>)
|
|
333
329
|
end
|
|
334
|
-
|
|
330
|
+
|
|
335
331
|
end
|
|
336
332
|
end
|
|
337
|
-
```
|
|
333
|
+
```
|
|
338
334
|
|
|
339
335
|
**app/person/record.rb** *(This is the view to view, edit, update, and delete a record)*
|
|
340
336
|
|
|
@@ -342,7 +338,7 @@ end
|
|
|
342
338
|
module App::Person::Record
|
|
343
339
|
extend Waxx::View
|
|
344
340
|
extend self
|
|
345
|
-
|
|
341
|
+
|
|
346
342
|
has(
|
|
347
343
|
:id,
|
|
348
344
|
:first_name,
|
|
@@ -350,23 +346,23 @@ module App::Person::Record
|
|
|
350
346
|
:email,
|
|
351
347
|
:bio
|
|
352
348
|
)
|
|
353
|
-
|
|
349
|
+
|
|
354
350
|
module Html
|
|
355
351
|
extend Waxx::Html
|
|
356
352
|
extend self
|
|
357
|
-
|
|
353
|
+
|
|
358
354
|
def get(x, data, message={})
|
|
359
355
|
App::Html.page(
|
|
360
356
|
title: "#{data['first_name']} #{data['last_name']}",
|
|
361
357
|
content: content(x, data)
|
|
362
358
|
)
|
|
363
359
|
end
|
|
364
|
-
|
|
360
|
+
|
|
365
361
|
def content(x, data)
|
|
366
362
|
# You put your HTML output here using:
|
|
367
363
|
%(<p>HTHL or a template engine</p>)
|
|
368
364
|
end
|
|
369
|
-
|
|
365
|
+
|
|
370
366
|
def post(x)
|
|
371
367
|
# Following a post, redirect to the list view
|
|
372
368
|
x.res.redirect "/person/list"
|
|
@@ -425,7 +421,7 @@ Then in the list view, we can add the company that the person is associated with
|
|
|
425
421
|
module App::Person::List
|
|
426
422
|
extend Waxx::View
|
|
427
423
|
extend self
|
|
428
|
-
|
|
424
|
+
|
|
429
425
|
has(
|
|
430
426
|
:id,
|
|
431
427
|
:first_name,
|
|
@@ -435,7 +431,7 @@ module App::Person::List
|
|
|
435
431
|
)
|
|
436
432
|
end
|
|
437
433
|
```
|
|
438
|
-
|
|
434
|
+
|
|
439
435
|
In this case the attribute "company_name" will be added to the view and is the value of the "name" field in the company table. The syntax for this is `<name>: <relationship_name (as defined in the object)>.<field>`.
|
|
440
436
|
|
|
441
437
|
### LEFT JOIN (is: name:table.field+)
|
|
@@ -462,10 +458,10 @@ end
|
|
|
462
458
|
|
|
463
459
|
*Note: The + sign after the related attribute make this join a left join (Oracle style)*
|
|
464
460
|
|
|
465
|
-
INNER JOIN (If you don't want to show invoices with no items):
|
|
461
|
+
INNER JOIN (If you don't want to show invoices with no items):
|
|
466
462
|
|
|
467
463
|
`id: {pkey: true, is:"items: invoice_item.invoice_id"}`
|
|
468
|
-
|
|
464
|
+
|
|
469
465
|
LEFT JOIN (If you want to show invoices with no items):
|
|
470
466
|
|
|
471
467
|
`id: {pkey: true, is:"items: invoice_item.invoice_id+"}`
|
|
@@ -496,7 +492,7 @@ This will show a list of all invoices and the items on the invoices:
|
|
|
496
492
|
module App::Invoice::Items
|
|
497
493
|
extend Waxx::View
|
|
498
494
|
extend self
|
|
499
|
-
|
|
495
|
+
|
|
500
496
|
has(
|
|
501
497
|
:id,
|
|
502
498
|
:invoice_date,
|
|
@@ -509,14 +505,14 @@ module App::Invoice::Items
|
|
|
509
505
|
)
|
|
510
506
|
end
|
|
511
507
|
```
|
|
512
|
-
|
|
508
|
+
|
|
513
509
|
This will generate the following SQL:
|
|
514
510
|
|
|
515
511
|
```sql
|
|
516
|
-
SELECT invoice.id, invoice.invoice_date, company.name as company, product.name as product,
|
|
512
|
+
SELECT invoice.id, invoice.invoice_date, company.name as company, product.name as product,
|
|
517
513
|
items.description as desc, items.quantity as qty, items.unit_price as price,
|
|
518
514
|
(items.quantity * items.unit_price) as total
|
|
519
|
-
FROM invoice
|
|
515
|
+
FROM invoice
|
|
520
516
|
LEFT JOIN invoice_item AS items ON invoice.id = invoice_item.invoice_id
|
|
521
517
|
INNER JOIN company ON invoice.customer_id = company.id
|
|
522
518
|
INNER JOIN product ON items.product_id = product.id
|
|
@@ -535,7 +531,7 @@ The join table is just another object in Waxx
|
|
|
535
531
|
module App::Usr
|
|
536
532
|
extend Waxx::Pg
|
|
537
533
|
extend self
|
|
538
|
-
|
|
534
|
+
|
|
539
535
|
has({
|
|
540
536
|
id: {pkey: true, is:"group_member: usr_grp.usr_id+"},
|
|
541
537
|
email: {validate: "email"},
|
|
@@ -547,7 +543,7 @@ The join table is just another object in Waxx
|
|
|
547
543
|
module App::Grp
|
|
548
544
|
extend Waxx::Pg
|
|
549
545
|
extend self
|
|
550
|
-
|
|
546
|
+
|
|
551
547
|
has({
|
|
552
548
|
id: {pkey: true, is:"group_members: usr_grp.grp_id+"},
|
|
553
549
|
name: {required: true}
|
|
@@ -558,19 +554,19 @@ The join table is just another object in Waxx
|
|
|
558
554
|
module App::UsrGrp
|
|
559
555
|
extend Waxx::Pg
|
|
560
556
|
extend self
|
|
561
|
-
|
|
557
|
+
|
|
562
558
|
has({
|
|
563
559
|
id: {pkey: true},
|
|
564
560
|
usr_id: {required: true, is:"usr:usr.id"},
|
|
565
561
|
grp_id: {required: true, is:"grp:grp.id"}
|
|
566
562
|
})
|
|
567
563
|
end
|
|
568
|
-
|
|
564
|
+
|
|
569
565
|
# View that joins all three tables (show all users and groups they are in)
|
|
570
566
|
module App::Usr::Groups
|
|
571
567
|
extend Waxx::View
|
|
572
568
|
extend self
|
|
573
|
-
|
|
569
|
+
|
|
574
570
|
has(
|
|
575
571
|
:id,
|
|
576
572
|
:email,
|
|
@@ -616,7 +612,7 @@ Each slash-delimited argument after the first two are treated as arguments to th
|
|
|
616
612
|
module App::Artist
|
|
617
613
|
extend Waxx::Pg
|
|
618
614
|
extend self
|
|
619
|
-
|
|
615
|
+
|
|
620
616
|
runs(
|
|
621
617
|
in: {
|
|
622
618
|
desc: "Show a list of artists in an area",
|
|
@@ -628,7 +624,7 @@ module App::Artist
|
|
|
628
624
|
end
|
|
629
625
|
```
|
|
630
626
|
|
|
631
|
-
In this case all three parameters are required. An error will be raised if the city is missing.
|
|
627
|
+
In this case all three parameters are required. An error will be raised if the city is missing.
|
|
632
628
|
There are two options: Add default values or use a proc instead of a lambda:
|
|
633
629
|
|
|
634
630
|
```
|
|
@@ -643,10 +639,10 @@ get: -> (x, country="us", state_prov="", city="") { }
|
|
|
643
639
|
```
|
|
644
640
|
|
|
645
641
|
NOTE: You can use `return` in `lambda` and `->` constructs, but you need to use `break` in `proc` constructs to stop processing.
|
|
646
|
-
|
|
642
|
+
|
|
647
643
|
### Variable Act / not_found
|
|
648
644
|
|
|
649
|
-
What if you want the act be a variable like `/artist/david-bowie` or `/artist/motorhead`?
|
|
645
|
+
What if you want the act be a variable like `/artist/david-bowie` or `/artist/motorhead`?
|
|
650
646
|
|
|
651
647
|
You define **`not_found`** in your Object runs method:
|
|
652
648
|
|
|
@@ -654,7 +650,7 @@ You define **`not_found`** in your Object runs method:
|
|
|
654
650
|
module App::Artist
|
|
655
651
|
extend Waxx::Pg
|
|
656
652
|
extend self
|
|
657
|
-
|
|
653
|
+
|
|
658
654
|
runs(
|
|
659
655
|
default: "list",
|
|
660
656
|
list: {
|
|
@@ -699,7 +695,7 @@ Waxx includes a full user and session management system. The following apps are
|
|
|
699
695
|
Using these apps allow you to add users and groups and put users in groups. You define your access control lists for each method. There are several levels of permissions. The following seven code blocks are parts of the same file:
|
|
700
696
|
|
|
701
697
|
### Example ACLs
|
|
702
|
-
ACLs are defined as a attribute (`acl: [nil|string|array|hash|lambda]`) of each method options hash.
|
|
698
|
+
ACLs are defined as a attribute (`acl: [nil|string|array|hash|lambda]`) of each method options hash.
|
|
703
699
|
|
|
704
700
|
The following code blocks are different examples of the acl attribute in practice.
|
|
705
701
|
|
|
@@ -709,7 +705,7 @@ The following code blocks are different examples of the acl attribute in practic
|
|
|
709
705
|
module App::Product
|
|
710
706
|
extend Waxx::Pg
|
|
711
707
|
extend self
|
|
712
|
-
|
|
708
|
+
|
|
713
709
|
runs(
|
|
714
710
|
default: "list",
|
|
715
711
|
```
|
|
@@ -777,7 +773,7 @@ If the proc or lambda returns true, then the user is allowed to proceed, otherwi
|
|
|
777
773
|
|
|
778
774
|
```ruby
|
|
779
775
|
special: {
|
|
780
|
-
desc: "View and edit a product from a specific IP
|
|
776
|
+
desc: "View and edit a product from a specific IP
|
|
781
777
|
or if the user has a secret key in their session",
|
|
782
778
|
acl: -> (x) {
|
|
783
779
|
x.req.env['X-REAL-IP'] == "10.10.10.10" or x.usr['secret'] == "let-me-in"
|
|
@@ -812,10 +808,10 @@ End the object file
|
|
|
812
808
|
|
|
813
809
|
A fast JSON response for an autocomplete form field
|
|
814
810
|
|
|
815
|
-
If you want to have a quick JSON response for an autocomplete -- Just use a Waxx::Object and bypass the Waxx::View and layout (Json, HTML, etc.).
|
|
811
|
+
If you want to have a quick JSON response for an autocomplete -- Just use a Waxx::Object and bypass the Waxx::View and layout (Json, HTML, etc.).
|
|
816
812
|
Direct access is available to the database driver with `x.db.app` where `app` is the name of the database connection defined in your config.yaml file.
|
|
817
|
-
In this case, as a user types in an autocomplete input box, the browser sends a request to: `/artist/autocomplete.json?q=da`
|
|
818
|
-
When the .json extension is used, the response content type will be application/json.
|
|
813
|
+
In this case, as a user types in an autocomplete input box, the browser sends a request to: `/artist/autocomplete.json?q=da`
|
|
814
|
+
When the .json extension is used, the response content type will be application/json.
|
|
819
815
|
What the user types would be in the `q` attribute.
|
|
820
816
|
|
|
821
817
|
PostgreSQL DB:
|
|
@@ -834,8 +830,8 @@ module App::Artist
|
|
|
834
830
|
desc: "Show a list of artists that match the 'q' param",
|
|
835
831
|
get: -> (x) {
|
|
836
832
|
x << x.db.app.exec("
|
|
837
|
-
SELECT id, name
|
|
838
|
-
FROM artist
|
|
833
|
+
SELECT id, name
|
|
834
|
+
FROM artist
|
|
839
835
|
WHERE name ILIKE $1
|
|
840
836
|
ORDER BY name
|
|
841
837
|
LIMIT 20",
|
|
@@ -870,7 +866,7 @@ module App::Artist
|
|
|
870
866
|
end
|
|
871
867
|
```
|
|
872
868
|
|
|
873
|
-
Both of these should return a response in less than one millisecond (assuming your data is indexed and running on
|
|
869
|
+
Both of these should return a response in less than one millisecond (assuming your data is indexed and running on decent hardware).
|
|
874
870
|
|
|
875
871
|
That is the intro. Give it a whirl.
|
|
876
872
|
|
data/lib/waxx/app.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Waxx::App
|
|
|
27
27
|
# The layout of the error page (html) is defined in app/app/error/html.rb
|
|
28
28
|
def not_found(x, title:"Not Found", message:nil)
|
|
29
29
|
begin
|
|
30
|
-
if message.nil?
|
|
30
|
+
if message.nil? and @runs[:website] and @runs[:website][:page]
|
|
31
31
|
return @runs[:website][:page][:get].call(x, *(x.args))
|
|
32
32
|
end
|
|
33
33
|
rescue => e
|
|
@@ -66,7 +66,7 @@ module Waxx::App
|
|
|
66
66
|
# 5. args: The args to pass to the method (after x) (Array)
|
|
67
67
|
#
|
|
68
68
|
# Example: `App.run(x, :person, :record, :get, [1])` will call the get method with the parameter "1" of the record handler defined in App::Person
|
|
69
|
-
def run(x, app, act, meth, args)
|
|
69
|
+
def run(x, app, act, meth, args=[])
|
|
70
70
|
if @runs[app.to_sym][act][meth.to_sym]
|
|
71
71
|
begin
|
|
72
72
|
@runs[app.to_sym][act][meth.to_sym][x, *args]
|
|
@@ -100,7 +100,11 @@ module Waxx::App
|
|
|
100
100
|
# Layouts in app/app/error/*
|
|
101
101
|
def error(x, status:200, type:"request", title:"An error occurred", message:"", args: [])
|
|
102
102
|
x.res.status = status
|
|
103
|
-
App[:app_error][type.to_sym]
|
|
103
|
+
if App[:app_error][type.to_sym]
|
|
104
|
+
App[:app_error][type.to_sym][:get][x, title, message, *args]
|
|
105
|
+
else
|
|
106
|
+
x << "ERROR: #{title} - #{message}"
|
|
107
|
+
end
|
|
104
108
|
end
|
|
105
109
|
|
|
106
110
|
##
|
|
@@ -158,6 +162,8 @@ module Waxx::App
|
|
|
158
162
|
|
|
159
163
|
def login_needed(x)
|
|
160
164
|
if x.ext == "json"
|
|
165
|
+
x.res.status = 400
|
|
166
|
+
x << {ok: false, msg: 'Login needed: Session did not pass ACL'}
|
|
161
167
|
else
|
|
162
168
|
App::Html.render(x,
|
|
163
169
|
title: "Please Login",
|
data/lib/waxx/console.rb
CHANGED
|
@@ -112,16 +112,19 @@ module Waxx::Console
|
|
|
112
112
|
require 'irb'
|
|
113
113
|
puts "waxx console"
|
|
114
114
|
#help = "Use the source, Luke"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
begin
|
|
116
|
+
x = Waxx::Console.x
|
|
117
|
+
binding.irb
|
|
118
|
+
rescue
|
|
119
|
+
IRB.setup(nil)
|
|
120
|
+
workspace = IRB::WorkSpace.new(self)
|
|
121
|
+
irb = IRB::Irb.new(workspace)
|
|
122
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
|
123
|
+
irb.eval_input
|
|
124
|
+
require 'lib/waxx/irb.rb'
|
|
125
|
+
@x = Waxx::Console.x
|
|
126
|
+
IRB.start_session(self) #"#{opts[:base]}/lib/waxx/irb_env.rb")
|
|
127
|
+
end
|
|
125
128
|
else
|
|
126
129
|
puts "Error: You need to call 'waxx console' from the root of a waxx installation."
|
|
127
130
|
exit 1
|
|
@@ -159,7 +162,8 @@ module Waxx::Console
|
|
|
159
162
|
File.open(m_file, "w"){|f|
|
|
160
163
|
f.puts "BEGIN;\n\n\n\nCOMMIT;"
|
|
161
164
|
}
|
|
162
|
-
|
|
165
|
+
puts "Created #{m_file}"
|
|
166
|
+
system "/usr/bin/env #{ENV['EDITOR'] || 'vim'} #{m_file}"
|
|
163
167
|
end
|
|
164
168
|
|
|
165
169
|
def test(target, opts)
|
data/lib/waxx/database.rb
CHANGED
|
@@ -62,7 +62,7 @@ module Waxx::Database
|
|
|
62
62
|
def migrate(db_only=nil, opts={})
|
|
63
63
|
dbs = connections
|
|
64
64
|
dbs.each{|name, db|
|
|
65
|
-
next if db_only and db_only !=
|
|
65
|
+
next if db_only and db_only.to_sym != name
|
|
66
66
|
puts "Migrating: db.#{name}"
|
|
67
67
|
# get the latest version
|
|
68
68
|
latest = db.exec("SELECT value FROM waxx WHERE name = 'db.#{name}.migration.last'").first['value']
|
|
@@ -77,4 +77,12 @@ module Waxx::Database
|
|
|
77
77
|
puts "Migration complete"
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
def [](name)
|
|
81
|
+
app[name]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def collection(name)
|
|
85
|
+
app[name]
|
|
86
|
+
end
|
|
87
|
+
|
|
80
88
|
end
|
data/lib/waxx/encrypt.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Waxx::Encrypt
|
|
|
12
12
|
when :b64
|
|
13
13
|
Base64.encode64(aes.update(str.to_s) + aes.final).chomp
|
|
14
14
|
when :url
|
|
15
|
-
|
|
15
|
+
Waxx::Http.escape(Base64.encode64(aes.update(str.to_s) + aes.final).chomp)
|
|
16
16
|
when :bin
|
|
17
17
|
aes.update(str.to_s) + aes.final
|
|
18
18
|
else
|
|
@@ -28,7 +28,7 @@ module Waxx::Encrypt
|
|
|
28
28
|
when :b64
|
|
29
29
|
aes.update(Base64.decode64(str.to_s + "\n")) + aes.final
|
|
30
30
|
when :url
|
|
31
|
-
aes.update(Base64.decode64(
|
|
31
|
+
aes.update(Base64.decode64(Waxx::Http.unescape(str.to_s) + "\n")) + aes.final
|
|
32
32
|
when :bin
|
|
33
33
|
aes.update(str.to_s) + aes.final
|
|
34
34
|
else
|
data/lib/waxx/http.rb
CHANGED
|
@@ -8,9 +8,10 @@ module Waxx::Http
|
|
|
8
8
|
ContentTypes
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def
|
|
11
|
+
def content_type(t, default="application/octet-stream")
|
|
12
12
|
ContentTypes[t.to_sym] || default
|
|
13
13
|
end
|
|
14
|
+
alias ctype content_type
|
|
14
15
|
|
|
15
16
|
def time(t=Time.new.utc)
|
|
16
17
|
t.strftime('%a, %d %b %Y %H:%M:%S UTC')
|
|
@@ -116,15 +117,20 @@ module Waxx::Http
|
|
|
116
117
|
if %w(PUT POST PATCH).include? meth
|
|
117
118
|
data = io.read(env['Content-Length'].to_i)
|
|
118
119
|
Waxx.debug "data.size: #{data.size} #{env['Content-Type']}"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
if env['Content-Length'].to_i == 0
|
|
121
|
+
post = {}.freeze
|
|
122
|
+
data = nil
|
|
123
|
+
else
|
|
124
|
+
case (env['Content-Type'] || env['content-type'] || env['Content-type'])
|
|
125
|
+
when /x-www-form-urlencoded/
|
|
126
|
+
post = query_string_to_hash(data).freeze
|
|
127
|
+
when /multipart/
|
|
128
|
+
post = parse_multipart(env, data).freeze
|
|
129
|
+
when /json/
|
|
130
|
+
post = (JSON.parse(data)).freeze
|
|
131
|
+
else
|
|
132
|
+
post = data.freeze
|
|
133
|
+
end
|
|
128
134
|
end
|
|
129
135
|
else
|
|
130
136
|
post = {}.freeze
|
data/lib/waxx/mongodb.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
3
|
|
|
4
4
|
module Waxx::Mongodb
|
|
5
|
+
extend self
|
|
5
6
|
|
|
6
7
|
attr :db
|
|
7
8
|
attr :table
|
|
@@ -20,6 +21,10 @@ module Waxx::Mongodb
|
|
|
20
21
|
has(cols) if cols
|
|
21
22
|
end
|
|
22
23
|
|
|
24
|
+
def connect(str)
|
|
25
|
+
Mongo::Client.new(str).database
|
|
26
|
+
end
|
|
27
|
+
|
|
23
28
|
def has(opts=nil)
|
|
24
29
|
init if @table.nil?
|
|
25
30
|
return @columns if opts.nil?
|
|
@@ -45,6 +50,10 @@ module Waxx::Mongodb
|
|
|
45
50
|
}
|
|
46
51
|
end
|
|
47
52
|
|
|
53
|
+
def connect(conf)
|
|
54
|
+
::Mongo::Client.new(conf).database
|
|
55
|
+
end
|
|
56
|
+
|
|
48
57
|
def [](n)
|
|
49
58
|
@columns[n.to_sym]
|
|
50
59
|
end
|
data/lib/waxx/patch.rb
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
3
|
|
|
4
4
|
# Patches to Ruby Classes
|
|
5
|
+
class BigDecimal
|
|
6
|
+
def to_json(*a)
|
|
7
|
+
to_f.to_json(*a)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
5
10
|
class Date
|
|
6
11
|
# HTML format for a date
|
|
7
12
|
def h
|
|
@@ -45,7 +50,8 @@ end
|
|
|
45
50
|
class Hash
|
|
46
51
|
# Add an symbol/string indifferent access to a hash
|
|
47
52
|
def /(k)
|
|
48
|
-
self[k.to_sym]
|
|
53
|
+
return self[k.to_sym] if self.has_key?(k.to_sym)
|
|
54
|
+
self[k.to_s]
|
|
49
55
|
end
|
|
50
56
|
end
|
|
51
57
|
class NilClass
|
|
@@ -64,6 +70,10 @@ class NilClass
|
|
|
64
70
|
def to_sym
|
|
65
71
|
"".to_sym
|
|
66
72
|
end
|
|
73
|
+
# Nil is empty
|
|
74
|
+
def empty?
|
|
75
|
+
true
|
|
76
|
+
end
|
|
67
77
|
end
|
|
68
78
|
class Numeric
|
|
69
79
|
# HTML format (self -- no escaping needed)
|
|
@@ -82,6 +92,18 @@ class Numeric
|
|
|
82
92
|
return x if size == 0
|
|
83
93
|
x << (d + (num_parts[1].to_s + "0000000")[0,size])
|
|
84
94
|
end
|
|
95
|
+
def ordinal
|
|
96
|
+
case self % 100
|
|
97
|
+
when 11, 12, 13 then "#{self}th"
|
|
98
|
+
else
|
|
99
|
+
case self % 10
|
|
100
|
+
when 1 then "#{self}st"
|
|
101
|
+
when 2 then "#{self}nd"
|
|
102
|
+
when 3 then "#{self}rd"
|
|
103
|
+
else "#{self}th"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
85
107
|
end
|
|
86
108
|
class String
|
|
87
109
|
# Escape HTML entities
|
|
@@ -97,6 +119,10 @@ class String
|
|
|
97
119
|
return x if size == 0
|
|
98
120
|
x << (d + (num_parts[1].to_s + "0000000")[0,size])
|
|
99
121
|
end
|
|
122
|
+
# Capitalize all words
|
|
123
|
+
def capitalize_all
|
|
124
|
+
split(/[ _]/).map{|l| l.capitalize}.join(' ')
|
|
125
|
+
end
|
|
100
126
|
end
|
|
101
127
|
class Time
|
|
102
128
|
# HTML format
|
|
@@ -130,7 +156,6 @@ class TrueClass
|
|
|
130
156
|
raise "Unknown format in TrueClass.f: #{format}. Needs to be :yn, :tf, :icon, or :num."
|
|
131
157
|
end
|
|
132
158
|
end
|
|
133
|
-
|
|
134
159
|
# Show true as 1
|
|
135
160
|
def to_i
|
|
136
161
|
1
|
data/lib/waxx/pdf.rb
CHANGED
|
@@ -41,12 +41,12 @@ module Waxx::Pdf
|
|
|
41
41
|
return_file(x)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def render_file(x, pdf)
|
|
45
|
-
pdf.render_file
|
|
44
|
+
def render_file(x, pdf, path)
|
|
45
|
+
pdf.render_file path
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def return_file(x)
|
|
49
|
-
File.open(
|
|
48
|
+
def return_file(x, path)
|
|
49
|
+
File.open(path, "rb"){|f| x << f.read}
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def show_grid(pdf)
|
data/lib/waxx/pg.rb
CHANGED
|
@@ -143,7 +143,16 @@ module Waxx::Pg
|
|
|
143
143
|
#[sql.join(" "), vals.flatten]
|
|
144
144
|
Waxx.debug sql
|
|
145
145
|
Waxx.debug vals.join(", ")
|
|
146
|
-
|
|
146
|
+
begin
|
|
147
|
+
x.db[@db].exec(sql.join(" "), vals.flatten)
|
|
148
|
+
rescue => e
|
|
149
|
+
if e =~ /connection/
|
|
150
|
+
x.db[@db].reset
|
|
151
|
+
x.db[@db].exec(sql.join(" "), vals.flatten)
|
|
152
|
+
else
|
|
153
|
+
raise e
|
|
154
|
+
end
|
|
155
|
+
end
|
|
147
156
|
end
|
|
148
157
|
|
|
149
158
|
def get_by_id(x, id, select=nil, view:nil)
|
|
@@ -151,6 +160,11 @@ module Waxx::Pg
|
|
|
151
160
|
end
|
|
152
161
|
alias by_id get_by_id
|
|
153
162
|
|
|
163
|
+
def get_by_ulid(x, ulid, select=nil, view:nil)
|
|
164
|
+
get(x, select: select, view: view, where: ["ulid = $1", [ulid]]).first
|
|
165
|
+
end
|
|
166
|
+
alias by_ulid get_by_ulid
|
|
167
|
+
|
|
154
168
|
def post(x, data, cols:nil, returning:nil, view:nil, &blk)
|
|
155
169
|
if view
|
|
156
170
|
cols = view.columns.select{|n,c| c[:table] == @table}
|
|
@@ -193,9 +207,7 @@ module Waxx::Pg
|
|
|
193
207
|
vals = []
|
|
194
208
|
ret = []
|
|
195
209
|
i = 1
|
|
196
|
-
Waxx.debug "data: #{data}"
|
|
197
210
|
cols.each{|n,v|
|
|
198
|
-
Waxx.debug "col: #{n}: #{v.inspect}"
|
|
199
211
|
if data.has_key? n.to_s or data.has_key? n.to_sym
|
|
200
212
|
set << "#{n} = $#{i}"
|
|
201
213
|
vals << cast(v, data/n)
|
|
@@ -208,10 +220,10 @@ module Waxx::Pg
|
|
|
208
220
|
vals << id
|
|
209
221
|
Waxx.debug(sql)
|
|
210
222
|
Waxx.debug(vals)
|
|
211
|
-
x.db[@db].exec(sql, vals).first
|
|
223
|
+
x.db[@db].exec(sql, vals).first
|
|
212
224
|
end
|
|
213
225
|
alias patch put
|
|
214
|
-
|
|
226
|
+
|
|
215
227
|
def put_post(x, id, data, cols:nil, returning:nil, view: nil)
|
|
216
228
|
q = nil
|
|
217
229
|
q = get_by_id(x, id, @pkey) if id.to_i > 0
|
|
@@ -230,8 +242,8 @@ module Waxx::Pg
|
|
|
230
242
|
end
|
|
231
243
|
end
|
|
232
244
|
|
|
233
|
-
def delete(x, id)
|
|
234
|
-
x.db[@db].exec("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
|
|
245
|
+
def delete(x, id, where: nil)
|
|
246
|
+
x.db[@db].exec("DELETE FROM #{@table} WHERE #{@pkey} = $1 #{where}", [id])
|
|
235
247
|
end
|
|
236
248
|
|
|
237
249
|
def order(req_order, default_order='')
|
data/lib/waxx/res.rb
CHANGED
|
@@ -84,8 +84,20 @@ module Waxx
|
|
|
84
84
|
def complete
|
|
85
85
|
re = out.join
|
|
86
86
|
headers["Content-Length"] = re.bytesize
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
begin
|
|
88
|
+
server.print head
|
|
89
|
+
server.print re
|
|
90
|
+
# Connection reset by peer
|
|
91
|
+
rescue Errno::ECONNRESET => e
|
|
92
|
+
Waxx.debug(e.class)
|
|
93
|
+
Waxx.debug(e)
|
|
94
|
+
Waxx.debug(e.backtrace.join("\n"))
|
|
95
|
+
# Broken pipe
|
|
96
|
+
rescue Errno::EPIPE => e
|
|
97
|
+
Waxx.debug(e.class)
|
|
98
|
+
Waxx.debug(e)
|
|
99
|
+
Waxx.debug(e.backtrace.join("\n"))
|
|
100
|
+
end
|
|
89
101
|
end
|
|
90
102
|
|
|
91
103
|
def cookie(name:"", value:nil, domain:nil, expires:nil, path:"/", secure:true, http_only: false, same_site: "Lax")
|
data/lib/waxx/server.rb
CHANGED
|
@@ -17,18 +17,17 @@ module Waxx::Server
|
|
|
17
17
|
attr :queue
|
|
18
18
|
|
|
19
19
|
def parse_uri(r)
|
|
20
|
-
Waxx.debug "parse_uri"
|
|
20
|
+
Waxx.debug "parse_uri: #{r}", 7
|
|
21
21
|
meth, uri, ver = r.split(" ")
|
|
22
22
|
path, params = uri.split("?", 2)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
parts = path.split('/')
|
|
24
|
+
ext = parts.last.include?('.') ? parts.last.split('.').last : Waxx['default']['ext'] rescue Waxx['default']['ext']
|
|
25
|
+
parts[parts.size - 1] = parts.last.to_s.sub(/.#{ext}$/,'') if parts.size > 0
|
|
26
|
+
app = parts[1].to_s.empty? ? Waxx['default']['app'] : parts[1]
|
|
27
|
+
act = parts[2].to_s.empty? ? (App[app.to_sym][:default] || Waxx['default']['act']) : parts[2] rescue Waxx['default']['act']
|
|
28
|
+
args = parts.slice(3,99) || []
|
|
29
|
+
oid = args.first.to_s.gsub(/[^0-9]/,"").to_i rescue 0
|
|
30
30
|
get = Waxx::Http.query_string_to_hash(params).freeze
|
|
31
|
-
Waxx.debug "parse_uri.oid #{oid}"
|
|
32
31
|
[meth, uri, app, act, oid, args, ext, get]
|
|
33
32
|
end
|
|
34
33
|
|
|
@@ -90,6 +89,7 @@ module Waxx::Server
|
|
|
90
89
|
end
|
|
91
90
|
#Waxx.debug "no-file"
|
|
92
91
|
env, head = Waxx::Http.parse_head(io)
|
|
92
|
+
Waxx.debug [Time.now.to_s, meth, uri].join(" "), 2
|
|
93
93
|
#Waxx.debug head, 9
|
|
94
94
|
cookie = Waxx::Http.parse_cookie(env['Cookie'])
|
|
95
95
|
begin
|
|
@@ -104,7 +104,17 @@ module Waxx::Server
|
|
|
104
104
|
Waxx.debug e.to_s, 1
|
|
105
105
|
ua = {}
|
|
106
106
|
end
|
|
107
|
-
|
|
107
|
+
begin
|
|
108
|
+
post, data = Waxx::Http.parse_data(env, meth, io, head)
|
|
109
|
+
rescue => e
|
|
110
|
+
post = nil
|
|
111
|
+
req = Waxx::Req.new(env, data, meth, uri, get, post, cookie, start_time).freeze
|
|
112
|
+
res = Waxx::Res.new(io, 400, default_response_headers(req, ext), [], [], [])
|
|
113
|
+
jobs = []
|
|
114
|
+
x = Waxx::X.new(req, res, usr, ua, db, meth.downcase.to_sym, app, act, oid, args, ext, jobs).freeze
|
|
115
|
+
fatal_error(x, e)
|
|
116
|
+
return finish(x, io)
|
|
117
|
+
end
|
|
108
118
|
req = Waxx::Req.new(env, data, meth, uri, get, post, cookie, start_time).freeze
|
|
109
119
|
res = Waxx::Res.new(io, 200, default_response_headers(req, ext), [], [], [])
|
|
110
120
|
jobs = []
|
|
@@ -171,7 +181,7 @@ module Waxx::Server
|
|
|
171
181
|
def fatal_error(x, e)
|
|
172
182
|
x.res.status = 503
|
|
173
183
|
puts "FATAL ERROR: #{e}\n#{e.backtrace}"
|
|
174
|
-
report = "APPLICATION ERROR\n=================\n\nUSR:\n\n#{x.usr.map{|n,v| "#{n}: #{v}"}.join("\n")}\n\nERROR:\n\n#{e}\n#{e.backtrace.join("\n")}\n\nENV:\n\n#{x.req.env.map{|n,v| "#{n}: #{v}"}.join("\n")}\n\nGET:\n\n#{x.req.get.map{|n,v| "#{n}: #{v}"}.join("\n")}\n\nPOST:\n\n#{x.req.post.map{|n,v| "#{n}: #{v}"}.join("\n")}\n\n"
|
|
184
|
+
report = "APPLICATION ERROR\n=================\n\nUSR:\n\n#{x.usr.map{|n,v| "#{n}: #{v}"}.join("\n") rescue nil}\n\nERROR:\n\n#{e}\n#{e.backtrace.join("\n")}\n\nENV:\n\n#{x.req.env.map{|n,v| "#{n}: #{v}"}.join("\n") rescue nil}\n\nGET:\n\n#{x.req.get.map{|n,v| "#{n}: #{v}"}.join("\n") rescue nil}\n\nPOST:\n\n#{x.req.post.map{|n,v| "#{n}: #{v}"}.join("\n") rescue nil}\n\n"
|
|
175
185
|
if Waxx['debug']['on_screen']
|
|
176
186
|
x << "<pre>#{report.h}</pre>"
|
|
177
187
|
else
|
|
@@ -189,16 +199,16 @@ module Waxx::Server
|
|
|
189
199
|
from_email = Waxx['site']['support_email']
|
|
190
200
|
subject = "[Bug] #{Waxx['site']['name']} #{x.meth}:#{x.req.uri}"
|
|
191
201
|
# Send email via DB
|
|
192
|
-
App::Email.post(x,
|
|
202
|
+
App::Email.post(x,
|
|
193
203
|
to_email: to_email,
|
|
194
204
|
from_email: from_email,
|
|
195
205
|
subject: subject,
|
|
196
206
|
body_text: report
|
|
197
|
-
|
|
207
|
+
)
|
|
198
208
|
rescue => e2
|
|
199
209
|
begin
|
|
200
210
|
# Send email directly
|
|
201
|
-
Mail.deliver do
|
|
211
|
+
::Mail.deliver do
|
|
202
212
|
from from_email
|
|
203
213
|
to to_email
|
|
204
214
|
subject subject
|
|
@@ -249,7 +259,13 @@ module Waxx::Server
|
|
|
249
259
|
Thread.current[:last_used] = Time.new.to_i
|
|
250
260
|
Waxx.debug "Create thread #{Thread.current[:name]}"
|
|
251
261
|
loop do
|
|
252
|
-
Waxx
|
|
262
|
+
Waxx.debug "Thread loop start", 9
|
|
263
|
+
begin
|
|
264
|
+
Waxx::Server.process_request(@@queue.pop, Thread.current[:db])
|
|
265
|
+
rescue => e
|
|
266
|
+
Waxx.debug "Error: process_request loop: #{e} #{e.backtrace}", 1
|
|
267
|
+
end
|
|
268
|
+
Waxx.debug "Thread loop end", 9
|
|
253
269
|
end
|
|
254
270
|
end
|
|
255
271
|
end
|
|
@@ -260,8 +276,13 @@ module Waxx::Server
|
|
|
260
276
|
@@queue = Queue.new
|
|
261
277
|
thread_count = Waxx['server']['min_threads'] || Waxx['server']['threads'] || 4
|
|
262
278
|
1.upto(thread_count).each do |i|
|
|
263
|
-
|
|
279
|
+
begin
|
|
280
|
+
create_thread(i)
|
|
281
|
+
rescue => e
|
|
282
|
+
Waxx.debug "Error creating thread #{i}: #{e}", 1
|
|
283
|
+
end
|
|
264
284
|
end
|
|
285
|
+
Waxx.debug "Created #{thread_count} threads", 7
|
|
265
286
|
thread_count
|
|
266
287
|
end
|
|
267
288
|
|
data/lib/waxx/version.rb
CHANGED
data/lib/waxx/view.rb
CHANGED
|
@@ -352,8 +352,8 @@ module Waxx::View
|
|
|
352
352
|
|
|
353
353
|
##
|
|
354
354
|
# Save data
|
|
355
|
-
def put_post(x, id, data, args:nil)
|
|
356
|
-
@object.put_post(x, id, data, view: self)
|
|
355
|
+
def put_post(x, id, data, args:nil, returning: nil)
|
|
356
|
+
@object.put_post(x, id, data, view: self, returning: returning)
|
|
357
357
|
end
|
|
358
358
|
alias post put_post
|
|
359
359
|
alias put put_post
|
data/lib/waxx/waxx.rb
CHANGED
|
@@ -42,7 +42,7 @@ module Waxx
|
|
|
42
42
|
# )
|
|
43
43
|
# # Set the level in config.yaml (debug.level) of what level or lower to ouutput
|
|
44
44
|
def debug(str, level=3)
|
|
45
|
-
puts
|
|
45
|
+
puts "#{Time.new} #{Thread.current[:name]} #{str}" if level <= Waxx['debug']['level'].to_i
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
##
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: waxx
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dan Fitzpatrick
|
|
@@ -11,26 +11,30 @@ bindir:
|
|
|
11
11
|
cert_chain:
|
|
12
12
|
- |
|
|
13
13
|
-----BEGIN CERTIFICATE-----
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
MIIEHDCCAoSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFkYW4v
|
|
15
|
+
REM9d2F4eC9EQz1pbzAeFw0xOTA3MjcwOTQ5MDVaFw0yMDA3MjYwOTQ5MDVaMBwx
|
|
16
|
+
GjAYBgNVBAMMEWRhbi9EQz13YXh4L0RDPWlvMIIBojANBgkqhkiG9w0BAQEFAAOC
|
|
17
|
+
AY8AMIIBigKCAYEAsglMsPILqXZwqDOa90PXxZ8BSxJun8XEUVuARccLbjrXVzc8
|
|
18
|
+
mSN+vbz7x3E+XSFJJnwvl3t/q596YsXXZe2L3igRewlegpGKvHl6txutdD87BBs/
|
|
19
|
+
2nFE0tdZPK7Z4zXJTU0DLhnW7P+kWk7/XbUdzK6OCLCwWi/c59X5XA0SqPALSaN/
|
|
20
|
+
LnHyP8RJ9Lgr+HO9t7ifCwnkY/vTnEQldTwMI1AtvA/vU8i0JC/1ga8Q3ZwdY9A3
|
|
21
|
+
uKwGy1aD8n9UgsJ575h/durNzzY45s070qJSypF20AORP78TM5qSYK26DQsRI2Gf
|
|
22
|
+
3mk+JxzxjEYHUaNrwFMDNwNUZC1rtC4ZJnm4rn7W28mV5EY6Y7uJklLLUR5TUIz6
|
|
23
|
+
CDn1xHloCqe0w7kjqYA2wgZmcDQep6njjeH4+MI0Zf6NQsDq2YvyfjWwQ4WjMKSB
|
|
24
|
+
AFwtLsp7uFKPrhQZzK/Tur6+elLrRXpmc/YFUvGKxdqQJnskUW30YMjTamAZ0pcp
|
|
25
|
+
eufQJs2fmy/dN/lHAgMBAAGjaTBnMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0G
|
|
26
|
+
A1UdDgQWBBTkpfOYyNV5n1gahXFWfTI+4c7yyjAWBgNVHREEDzANgQtkYW5Ad2F4
|
|
27
|
+
eC5pbzAWBgNVHRIEDzANgQtkYW5Ad2F4eC5pbzANBgkqhkiG9w0BAQsFAAOCAYEA
|
|
28
|
+
eeB09ej0LuKC3bFK5rqC+Kqq/CssiV/P9fYR4WZn7+rMYEW9tR8HnmWRs6gTd4OB
|
|
29
|
+
fpvNoGcFcUAJg7lMyluXh2U7dqk4NfcLJqtFEcqhbAbYPrET8rcdFflJ55h5JK2q
|
|
30
|
+
jBjBV06q8jkIFvRttqebb6A2EFl1aE4hyI0t0OJyj0lVRkW157roguS6RU47N4g0
|
|
31
|
+
2u/LLlP67FStO4uw3rUMYNcR1Rdc8feT8WzEom8cyitkSeRBeqQ5w1mo5thyXBwh
|
|
32
|
+
kRnGOP+Ij4VrBxI1uii2e2j/sXdf01lUfJvp1A4WQAAc+vP+qmFAUL9sA1RVbwDN
|
|
33
|
+
cNz8/vxCZDMuVKJElhaLN07fSimHTy5QiOc+EJjmht8HGVo6xeo8FPAGoyYf6VTP
|
|
34
|
+
PpuD1dp8JPvtbfHD2fCgY1Uds71F6B+K0b6ekXli5toqH/ZbYw3+6LFZz/FE5vUo
|
|
35
|
+
Wf5j8aPxUlS26tTkD8GmaWtlnRFSMQPLTGACyoCnF2sC5R1xr7Ab0VxwSm0/qDPN
|
|
32
36
|
-----END CERTIFICATE-----
|
|
33
|
-
date:
|
|
37
|
+
date: 2019-07-27 00:00:00.000000000 Z
|
|
34
38
|
dependencies: []
|
|
35
39
|
description: Waxx is a high performace REST/RPC hybrid web application development
|
|
36
40
|
framework.
|
|
@@ -132,8 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
136
|
- !ruby/object:Gem::Version
|
|
133
137
|
version: '0'
|
|
134
138
|
requirements: []
|
|
135
|
-
|
|
136
|
-
rubygems_version: 2.6.8
|
|
139
|
+
rubygems_version: 3.0.4
|
|
137
140
|
signing_key:
|
|
138
141
|
specification_version: 4
|
|
139
142
|
summary: A fast and flexible application development framework
|
metadata.gz.sig
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
N�����r��£���x{}��ܾ-�b�2+�֢��QL��UQ �$o@�ɽw�X@zy�L�z22�F�K&z|���]��{��6�W5��A��l����v�0�y��W�ѝa<�~��P�|�q2�bg�� �Й/Y�C� �ۭ]#�/,�f�̚�bU�P�V8���
|
|
2
|
+
+�q��
|
|
3
|
+
(J�jސ��Hm^@d�G�e�pu?s�v��lG-��
|
|
4
|
+
�a�0�dH��<lOK�t`&!?��[x��~�k�8���M!�.h�G�)SNM��a�i-��"3dڰ՝�M�F@
|