tangled
alpha
login
or
join now
lesbian.skin
/
glimit
4
fork
atom
this repo has no description
4
fork
atom
overview
issues
pulls
pipelines
๐ซ Add Mist and Wisp examples
Joris Hartog
2 years ago
399117b4
786aad1e
+216
-53
10 changed files
expand all
collapse all
unified
split
README.md
examples
mist
.gitignore
gleam.toml
manifest.toml
src
app.gleam
wisp
.gitignore
gleam.toml
manifest.toml
src
app
router.gleam
app.gleam
+1
-53
README.md
···
43
43
func("๐") // "Stop!"
44
44
```
45
45
46
46
-
A more practical example would be to use `glimit` to rate limit requests to a mist HTTP server:
47
47
-
48
48
-
```gleam
49
49
-
import glimit
50
50
-
51
51
-
52
52
-
fn handle_request(req: Request(Connection)) -> Response(ResponseData) {
53
53
-
let index =
54
54
-
response.new(200)
55
55
-
|> response.set_body(mist.Bytes(bytes_builder.new()))
56
56
-
let not_found =
57
57
-
response.new(404)
58
58
-
|> response.set_body(mist.Bytes(bytes_builder.new()))
59
59
-
60
60
-
case request.path_segments(req) {
61
61
-
[] -> index
62
62
-
_ -> not_found
63
63
-
}
64
64
-
}
65
65
-
66
66
-
fn get_identifier(req: Request(Connection)) -> Result(String, String) {
67
67
-
req.body
68
68
-
|> get_client_info
69
69
-
|> result.map(fn(client_info: ConnectionInfo) {
70
70
-
client_info.ip_address |> string.inspect
71
71
-
})
72
72
-
|> result.unwrap("unknown IP address")
73
73
-
}
74
74
-
75
75
-
pub fn main() {
76
76
-
let rate_limit_reached = fn(_req) -> {
77
77
-
response.new(429)
78
78
-
|> response.set_body(mist.Bytes(bytes_builder.new()))
79
79
-
}
80
80
-
81
81
-
let limiter =
82
82
-
glimit.new()
83
83
-
|> glimit.per_second(10)
84
84
-
|> glimit.burst_limit(100)
85
85
-
|> glimit.identifier(get_identifier)
86
86
-
|> glimit.on_limit_exceeded(rate_limit_reached)
87
87
-
|> glimit.build
88
88
-
89
89
-
let assert Ok(_) =
90
90
-
handle_request
91
91
-
|> glimit.apply(limiter)
92
92
-
|> mist.new
93
93
-
|> mist.port(8080)
94
94
-
|> mist.start_http
95
95
-
96
96
-
process.sleep_forever()
97
97
-
}
98
98
-
```
46
46
+
More practical examples can be found in the `examples/` directory, such as Wisp and Mist server examples.
99
47
100
48
101
49
## Constraints
+4
examples/mist/.gitignore
···
1
1
+
*.beam
2
2
+
*.ez
3
3
+
/build
4
4
+
erl_crash.dump
+12
examples/mist/gleam.toml
···
1
1
+
name = "app"
2
2
+
version = "1.0.0"
3
3
+
4
4
+
[dependencies]
5
5
+
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
6
6
+
glimit = { path = "../.." }
7
7
+
mist = ">= 2.0.0 and < 3.0.0"
8
8
+
gleam_http = ">= 3.6.0 and < 4.0.0"
9
9
+
gleam_erlang = ">= 0.26.0 and < 1.0.0"
10
10
+
11
11
+
[dev-dependencies]
12
12
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+28
examples/mist/manifest.toml
···
1
1
+
# This file was generated by Gleam
2
2
+
# You typically do not need to edit this file
3
3
+
4
4
+
packages = [
5
5
+
{ name = "birl", version = "1.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "5C66647D62BCB11FE327E7A6024907C4A17954EF22865FE0940B54A852446D01" },
6
6
+
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
7
7
+
{ name = "gleam_erlang", version = "0.26.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "3DF72F95F4716883FA51396FB0C550ED3D55195B541568CAF09745984FD37AD1" },
8
8
+
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
9
9
+
{ name = "gleam_otp", version = "0.12.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "CD5FC777E99673BDB390092DF85E34EAA6B8EE1882147496290AB3F45A4960B1" },
10
10
+
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
11
11
+
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
12
12
+
{ name = "glimit", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
13
13
+
{ name = "glisten", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "48EF7F6D1DCA877C2F49AF35CC33946C7129EEB05A114758A2CC569C708BFAF8" },
14
14
+
{ name = "gramps", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "3CCAA6E081225180D95C79679D383BBF51C8D1FDC1B84DA1DA444F628C373793" },
15
15
+
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
16
16
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
17
17
+
{ name = "mist", version = "2.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "981F12FC8BA0656B40099EC876D6F2BEE7B95593610F342E9AB0DC4E663A932F" },
18
18
+
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
19
19
+
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
20
20
+
]
21
21
+
22
22
+
[requirements]
23
23
+
gleam_erlang = { version = ">= 0.26.0 and < 1.0.0" }
24
24
+
gleam_http = { version = ">= 3.6.0 and < 4.0.0" }
25
25
+
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
26
26
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
27
27
+
glimit = { path = "../.." }
28
28
+
mist = { version = ">= 2.0.0 and < 3.0.0" }
+59
examples/mist/src/app.gleam
···
1
1
+
import gleam/bytes_builder
2
2
+
import gleam/erlang/process
3
3
+
import gleam/http/request.{type Request}
4
4
+
import gleam/http/response.{type Response}
5
5
+
import gleam/result
6
6
+
import gleam/string
7
7
+
import glimit
8
8
+
import mist.{
9
9
+
type Connection, type ConnectionInfo, type ResponseData, get_client_info,
10
10
+
}
11
11
+
12
12
+
fn handle_request(req: Request(Connection)) -> Response(ResponseData) {
13
13
+
let index =
14
14
+
response.new(200)
15
15
+
|> response.set_body(mist.Bytes(bytes_builder.from_string("Hello, world!")))
16
16
+
let not_found =
17
17
+
response.new(404)
18
18
+
|> response.set_body(mist.Bytes(bytes_builder.from_string("Not found")))
19
19
+
20
20
+
case request.path_segments(req) {
21
21
+
[] -> index
22
22
+
_ -> not_found
23
23
+
}
24
24
+
}
25
25
+
26
26
+
fn get_ip_address(req: Request(Connection)) -> String {
27
27
+
req.body
28
28
+
|> get_client_info
29
29
+
|> result.map(fn(client_info: ConnectionInfo) {
30
30
+
client_info.ip_address |> string.inspect
31
31
+
})
32
32
+
|> result.unwrap("unknown IP address")
33
33
+
}
34
34
+
35
35
+
pub fn main() {
36
36
+
let rate_limit_reached = fn(_req) {
37
37
+
response.new(429)
38
38
+
|> response.set_body(
39
39
+
mist.Bytes(bytes_builder.from_string("Too many requests")),
40
40
+
)
41
41
+
}
42
42
+
43
43
+
let limiter =
44
44
+
glimit.new()
45
45
+
|> glimit.per_second(1)
46
46
+
|> glimit.burst_limit(5)
47
47
+
|> glimit.identifier(get_ip_address)
48
48
+
|> glimit.on_limit_exceeded(rate_limit_reached)
49
49
+
|> glimit.build
50
50
+
51
51
+
let assert Ok(_) =
52
52
+
handle_request
53
53
+
|> glimit.apply(limiter)
54
54
+
|> mist.new
55
55
+
|> mist.port(8000)
56
56
+
|> mist.start_http
57
57
+
58
58
+
process.sleep_forever()
59
59
+
}
+4
examples/wisp/.gitignore
···
1
1
+
*.beam
2
2
+
*.ez
3
3
+
/build
4
4
+
erl_crash.dump
+16
examples/wisp/gleam.toml
···
1
1
+
name = "app"
2
2
+
version = "1.0.0"
3
3
+
description = "A Wisp example"
4
4
+
gleam = ">= 0.32.0"
5
5
+
6
6
+
[dependencies]
7
7
+
gleam_stdlib = "~> 0.30"
8
8
+
glimit = { path = "../.." }
9
9
+
wisp = "~> 1.1.0"
10
10
+
gleam_erlang = "~> 0.23"
11
11
+
mist = ">= 2.0.0 and < 3.0.0"
12
12
+
gleam_http = ">= 3.6.0 and < 4.0.0"
13
13
+
14
14
+
15
15
+
[dev-dependencies]
16
16
+
gleeunit = "~> 1.0"
+39
examples/wisp/manifest.toml
···
1
1
+
# This file was generated by Gleam
2
2
+
# You typically do not need to edit this file
3
3
+
4
4
+
packages = [
5
5
+
{ name = "birl", version = "1.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "5C66647D62BCB11FE327E7A6024907C4A17954EF22865FE0940B54A852446D01" },
6
6
+
{ name = "directories", version = "1.1.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "BDA521A4EB9EE3A7894F0DC863797878E91FF5C7826F7084B2E731E208BDB076" },
7
7
+
{ name = "envoy", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "CFAACCCFC47654F7E8B75E614746ED924C65BD08B1DE21101548AC314A8B6A41" },
8
8
+
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
9
9
+
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
10
10
+
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
11
11
+
{ name = "gleam_erlang", version = "0.26.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "3DF72F95F4716883FA51396FB0C550ED3D55195B541568CAF09745984FD37AD1" },
12
12
+
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
13
13
+
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
14
14
+
{ name = "gleam_otp", version = "0.12.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "CD5FC777E99673BDB390092DF85E34EAA6B8EE1882147496290AB3F45A4960B1" },
15
15
+
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
16
16
+
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
17
17
+
{ name = "glimit", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
18
18
+
{ name = "glisten", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "48EF7F6D1DCA877C2F49AF35CC33946C7129EEB05A114758A2CC569C708BFAF8" },
19
19
+
{ name = "gramps", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "3CCAA6E081225180D95C79679D383BBF51C8D1FDC1B84DA1DA444F628C373793" },
20
20
+
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
21
21
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
22
22
+
{ name = "marceau", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "5188D643C181EE350D8A20A3BDBD63AF7B6C505DE333CFBE05EF642ADD88A59B" },
23
23
+
{ name = "mist", version = "2.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "981F12FC8BA0656B40099EC876D6F2BEE7B95593610F342E9AB0DC4E663A932F" },
24
24
+
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
25
25
+
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
26
26
+
{ name = "simplifile", version = "2.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "BDD04F5D31D6D34E2EDFAEF0B68A6297AEC939888C3BFCE61133DE13857F6DA2" },
27
27
+
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
28
28
+
{ name = "thoas", version = "1.2.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A" },
29
29
+
{ name = "wisp", version = "1.1.0", build_tools = ["gleam"], requirements = ["directories", "exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "5B25E37E08A94039668D2ACF7B2D2A665BEAF4B48EFA8613010B4E3164137664" },
30
30
+
]
31
31
+
32
32
+
[requirements]
33
33
+
gleam_erlang = { version = "~> 0.23" }
34
34
+
gleam_http = { version = ">= 3.6.0 and < 4.0.0" }
35
35
+
gleam_stdlib = { version = "~> 0.30" }
36
36
+
gleeunit = { version = "~> 1.0" }
37
37
+
glimit = { path = "../.." }
38
38
+
mist = { version = ">= 2.0.0 and < 3.0.0" }
39
39
+
wisp = { version = "~> 1.1.0" }
+44
examples/wisp/src/app.gleam
···
1
1
+
import app/router
2
2
+
import gleam/erlang/process
3
3
+
import gleam/http/request
4
4
+
import gleam/result
5
5
+
import gleam/string_builder
6
6
+
import glimit
7
7
+
import mist
8
8
+
import wisp.{type Request}
9
9
+
import wisp/wisp_mist
10
10
+
11
11
+
pub fn main() {
12
12
+
// Setup a rate limiter.
13
13
+
let limiter =
14
14
+
glimit.new()
15
15
+
|> glimit.per_second(1)
16
16
+
|> glimit.burst_limit(5)
17
17
+
|> glimit.identifier(fn(req: Request) {
18
18
+
req
19
19
+
|> request.get_header("X-Forwarded-For")
20
20
+
|> result.unwrap("anonymous")
21
21
+
})
22
22
+
|> glimit.on_limit_exceeded(fn(_) {
23
23
+
let body = string_builder.from_string("<h1>Too many requests</h1>")
24
24
+
wisp.html_response(body, 429)
25
25
+
})
26
26
+
|> glimit.build
27
27
+
28
28
+
wisp.configure_logger()
29
29
+
30
30
+
let secret_key_base = wisp.random_string(64)
31
31
+
32
32
+
// Start the Mist web server.
33
33
+
let assert Ok(_) =
34
34
+
wisp_mist.handler(
35
35
+
router.handle_request
36
36
+
|> glimit.apply(limiter),
37
37
+
secret_key_base,
38
38
+
)
39
39
+
|> mist.new
40
40
+
|> mist.port(8000)
41
41
+
|> mist.start_http
42
42
+
43
43
+
process.sleep_forever()
44
44
+
}
+9
examples/wisp/src/app/router.gleam
···
1
1
+
import gleam/string_builder
2
2
+
import wisp.{type Request, type Response}
3
3
+
4
4
+
/// The HTTP request handler- your application!
5
5
+
///
6
6
+
pub fn handle_request(_req: Request) -> Response {
7
7
+
let body = string_builder.from_string("<h1>๐ Hi!</h1>")
8
8
+
wisp.html_response(body, 200)
9
9
+
}