Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a2165ea
[http] add forgotten HTTPRequest object
melkyades Apr 29, 2025
bf99646
[http] improve documentation
melkyades Apr 30, 2025
e72e3d9
[git] ignore built libs in image-segments dir
melkyades Apr 30, 2025
90d9ec6
[http] make uri varnames use {name} format instead of :name
melkyades Apr 30, 2025
240bd8f
[git] tell git *.st are actually smalltalk files to avoid github conf…
melkyades Apr 30, 2025
59b6e3a
[vm-cpp] make GCedRef hold an Object*, not assume it is always a Heap…
melkyades May 1, 2025
49fad99
[vm-cpp] make vm assume less things are HeapObject*, make them Object…
melkyades May 1, 2025
9d0dbf8
[vm-cpp] convert Object* ivars in Runtime and SExpressions to GCedRef…
melkyades May 1, 2025
7d661aa
[vm-cpp] convert GCSafepoint to GCGuard; now it can be used to enable…
melkyades May 1, 2025
c24d669
[vm-cpp] make compiled code executable code be nil instead of nullptr…
melkyades May 1, 2025
85cf30e
[vm-cpp] remove dead code
melkyades May 1, 2025
b9660dd
[vm-cpp] show a proper error message when a primitive implementation …
melkyades May 1, 2025
27edd07
[vm-cpp] make GC scan current regs
melkyades May 1, 2025
15be746
[vm-cpp] when decommiting memory, wipe it out and unmap it to block u…
melkyades May 1, 2025
86b9d66
[json] add json module
melkyades May 2, 2025
69f3995
[http] update ffi glue to support DELETE and POST
melkyades May 2, 2025
1fe1829
[http] make paramAt: return nil if parameter wasn't passed in request
melkyades May 2, 2025
6494dbf
[http] server doesn't know about selectors, it just evaluates handler…
melkyades May 2, 2025
3f30352
[http] update example to current http server api
melkyades May 2, 2025
2fc8094
[vm-cpp] implement primitive to get process BP (used in ensure)
melkyades May 2, 2025
d982eca
[kernel] add exceptionHandler accessor to Process
melkyades May 2, 2025
e2d5c2a
[webside] initial webside implementation, implementing /dialect and /…
melkyades May 2, 2025
0448f26
[vm-cpp] fix allocation of large spaces
melkyades May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.st text linguist-language=Smalltalk

4 changes: 4 additions & 0 deletions image-segments/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
*.json
*.ems
*.so
*.dll
*.dylib

4 changes: 2 additions & 2 deletions modules/Examples/HTTPServer/HTTPServerModule.st
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Class {
{ #category : #spec }
HTTPServerModule >> imports [
^{
#'HTTP.CPPHTTPServer' -> #(HTTPServer).
#FFI -> #(ExternalLibrary).
#'HTTP.CPPHTTPServer' -> #(HTTPServer).
}
]

Expand All @@ -32,7 +32,7 @@ HTTPServerModule >> main: arguments [
base := arguments at: 3 ifAbsent: ['/egg'].
server := HTTPServer new.
server
routeGET: base, '/hello/:name' to: #hello with: self.
routeGET: base, '/hello/{name}' to: [:req :res | self handle: req into: res with: #hello].
Kernel log: 'server configured, starting!', String cr.
server start.
^0
Expand Down
15 changes: 15 additions & 0 deletions modules/Examples/HTTPServer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# HTTP Server example

An example of an HTTP server based on cpp-httplib.
The CPPHTTPServer module contains an FFI interface to plain C wrappers
to cpp-httplib. Here we use those wrappers to create a blocking web
server.

## Building

You need to build the native cpp-httplib in HTTP/CPPHTTPServer/lib (see
its readme), then build this module and FFI

cd image-segments
make FFI.ems FFI.Posix.ems Examples.HTTPServer.ems

23 changes: 23 additions & 0 deletions modules/HTTP/CPPHTTPServer/HTTPRequest.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"
Copyright (c) 2024, Javier Pimás.
See (MIT) license in root directory.
"

Class {
#name : #HTTPRequest,
#superclass : #ExternalObject,
#category : #'CPPHTTPServer'
}

{ #category : #spec }
HTTPRequest >> paramAt: aString [
| addr |
addr := self class module library
request: handle asParameter
paramAt: aString externalCopy asParameter.

addr = 0 ifTrue: [^nil].

"should do better and look at encoding"
^String fromMemory: addr pointedMemory
]
8 changes: 4 additions & 4 deletions modules/HTTP/CPPHTTPServer/HTTPServer.st
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ Class {
}

{ #category : #spec }
HTTPServer >> handle: requestHandle with: handler into: responseHandle with: selector [
HTTPServer >> handle: requestHandle with: handler into: responseHandle [
| request response |
request := HTTPRequest new handle: requestHandle.
response := HTTPResponse new handle: responseHandle.
handler handle: request into: response with: selector.
handler evaluateWith: request with: response.
^responseHandle
]

Expand All @@ -29,11 +29,11 @@ HTTPServer >> library [
]

{ #category : #spec }
HTTPServer >> routeGET: uri to: selector with: handler [
HTTPServer >> routeGET: uri to: handler [
self library
server: self asParameter
GET: uri externalCopy asParameter
callback: [ :request :response | self handle: request with: handler into: response with: selector ] asCallback
callback: [ :request :response | self handle: request with: handler into: response ] asCallback
]

{ #category : #spec }
Expand Down
11 changes: 11 additions & 0 deletions modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,22 @@ HTTPServerLibrary >> newServer [
<cdecl: pointer Server_New()>
]

{ #category : #server }
HTTPServerLibrary >> server: aServer DELETE: url callback: aCallback [
<cdecl: void Server_Delete(pointer, pointer, pointer)>
]

{ #category : #server }
HTTPServerLibrary >> server: aServer GET: url callback: aCallback [
<cdecl: void Server_Get(pointer, pointer, pointer)>
]

{ #category : #server }
HTTPServerLibrary >> server: aServer POST: url callback: aCallback [
<cdecl: void Server_Post(pointer, pointer, pointer)>
]


{ #category : #server }
HTTPServerLibrary >> startServer: aServer [
<cdecl: void Server_Start(pointer)>
Expand Down
12 changes: 9 additions & 3 deletions modules/HTTP/CPPHTTPServer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@ egg/modules/HTTP/CPPHTTPServer/lib $
cmake -S . -B build && cmake --build build
```

The result should be a file called libhttpserver.so (linux), httpserver.dll (windows) or
something similar for your platform. This file will go to the build dir, you'll have to
copy it to some place in your egg's FFI path (simplest way: the place from where you run egg).
The result should be a file called libhttpserver.so (linux), httpserver.dll (windows),
httpserver.dylib or something similar for your platform.
This file will go to the build dir, you'll have to copy (or better, link) it to some
place in your egg's FFI path (simplest way: the place from where you run egg).

```
egg/image-segments $
ln -s ../modules/HTTP/CPPHTTPServer/lib/libhttpserver.so .
```

# Usage

Expand Down
12 changes: 10 additions & 2 deletions modules/HTTP/CPPHTTPServer/lib/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

typedef void(*server_callback)(const void *, const void *);

// in our uri convention we use {var} to denote a variable, but httplib uses :var
static std::string translateUriFormat(const std::string& uri) {
static const std::regex varPattern(R"(\{([a-zA-Z_][a-zA-Z0-9_]*)\})");
return std::regex_replace(uri, varPattern, ":$1");
}

extern "C" {

void* Server_New()
Expand All @@ -14,7 +20,7 @@ void Server_Get(void *cserver, char *url, void *ccallback)
{
httplib::Server *server = reinterpret_cast<httplib::Server*>(cserver);
server_callback callback = reinterpret_cast<server_callback>(ccallback);
server->Get(url, [callback](const httplib::Request &req, httplib::Response &res) {
server->Get(translateUriFormat(url), [callback](const httplib::Request &req, httplib::Response &res) {
callback(&req, &res);
});
}
Expand All @@ -33,7 +39,9 @@ char* Request_ParamAt(void *creq, char *key, char *type)
{
httplib::Request *req = reinterpret_cast<httplib::Request*>(creq);

return (char*)req->path_params.at(key).c_str();
auto &params = req->path_params;
auto it = params.find(key);
return it != params.end() ? (char*)it->second.c_str() : nullptr;
}

void Response_SetContent(void *cres, char *content, char *type)
Expand Down
21 changes: 21 additions & 0 deletions modules/JSON/BooleanAdaptor.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #BooleanAdaptor,
#superclass : #DataAdaptor,
#category : #JSON
}

{ #category : #services }
BooleanAdaptor >> dataFrom: aBoolean [
^aBoolean ifTrue: [1] ifFalse: [0]
]

{ #category : #services }
BooleanAdaptor >> objectFrom: anInteger [
^anInteger asBoolean
]

28 changes: 28 additions & 0 deletions modules/JSON/DataAdaptor.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #DataAdaptor,
#superclass : #Object,
#category : #JSON
}

{ #category : #services }
DataAdaptor >> dataFrom: anObject [
^anObject asString
]

{ #category : #testing }
DataAdaptor >> isEntityAdaptor [
^false
]

{ #category : #services }
DataAdaptor >> objectFrom: aString [
^(aString conform: [:ch | ch isDigit or: [#($+ $- $.) includes: ch]])
ifTrue: [aString asNumber]
ifFalse: [aString]
]

43 changes: 43 additions & 0 deletions modules/JSON/IdAdaptor.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #IdAdaptor,
#superclass : #DataAdaptor,
#instVars : [
'selector'
],
#category : #JSON
}

{ #category : #'instance creation' }
IdAdaptor class >> forName [
^self new selector: #name
]

{ #category : #services }
IdAdaptor >> dataFrom: anObject [
anObject isNil ifTrue: [^nil].
anObject isInteger ifTrue: [^anObject].
anObject isString ifTrue: [^anObject].
^selector evaluateWith: anObject
]

{ #category : #initialization }
IdAdaptor >> initialize [
super initialize.
selector := #id
]

{ #category : #services }
IdAdaptor >> objectFrom: anInteger [
^anInteger
]

{ #category : #accessing }
IdAdaptor >> selector: aSymbol [
selector := aSymbol
]

21 changes: 21 additions & 0 deletions modules/JSON/JsonAnySchema.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #JsonAnySchema,
#superclass : #JsonCombinedSchema,
#category : #JSON
}

{ #category : #accessing }
JsonAnySchema class >> typeName [
^'anyOf'
]

{ #category : #testing }
JsonAnySchema >> isAnySchema [
^true
]

79 changes: 79 additions & 0 deletions modules/JSON/JsonArraySchema.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #JsonArraySchema,
#superclass : #JsonSchema,
#instVars : [
'items',
'minItems',
'maxItems',
'uniqueItems'
],
#category : #JSON
}

{ #category : #converting }
JsonArraySchema >> asJson [
| json |
json := super asJson.
items notNil ifTrue: [json items: items asJson].
minItems notNil ifTrue: [json at: 'minItems' put: minItems].
maxItems notNil ifTrue: [json at: 'maxItems' put: maxItems].
^json
]

{ #category : #initialization }
JsonArraySchema >> initialize [
super initialize.
uniqueItems := false
]

{ #category : #testing }
JsonArraySchema >> isArraySchema [
^true
]

{ #category : #accessing }
JsonArraySchema >> items [
^items
]

{ #category : #accessing }
JsonArraySchema >> items: aJsonSchema [
items := aJsonSchema.
aJsonSchema parent: self
]

{ #category : #accessing }
JsonArraySchema >> maxItems [
^maxItems
]

{ #category : #accessing }
JsonArraySchema >> maxItems: aNumber [
maxItems := aNumber
]

{ #category : #accessing }
JsonArraySchema >> minItems [
^minItems
]

{ #category : #accessing }
JsonArraySchema >> minItems: aNumber [
minItems := aNumber
]

{ #category : #accessing }
JsonArraySchema >> uniqueItems [
^uniqueItems
]

{ #category : #accessing }
JsonArraySchema >> uniqueItems: aBoolean [
uniqueItems := aBoolean
]

16 changes: 16 additions & 0 deletions modules/JSON/JsonBooleanSchema.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"
Copyright (c) 2020 Aucerna.
See (MIT) license in root directory.
"

Class {
#name : #JsonBooleanSchema,
#superclass : #JsonPrimitiveSchema,
#category : #JSON
}

{ #category : #testing }
JsonBooleanSchema >> isBooleanSchema [
^true
]

Loading