Skip to content

Commit 8f59c06

Browse files
authored
Merge pull request #17 from ghivert/refactor/improvements
Upgrade the whole application
2 parents 6463869 + a8518fd commit 8f59c06

File tree

305 files changed

+5754
-23490
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

305 files changed

+5754
-23490
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ jobs:
1616
- name: Setup BEAM
1717
uses: erlef/setup-beam@v1
1818
with:
19-
otp-version: '26.0.2'
20-
gleam-version: '1.4.1'
19+
otp-version: '27.0.0'
20+
gleam-version: '1.6.2'
2121
rebar3-version: '3'
2222
# elixir-version: "1.15.4"
2323
- name: Download gleam dependencies
@@ -50,8 +50,8 @@ jobs:
5050
- name: Setup BEAM
5151
uses: erlef/setup-beam@v1
5252
with:
53-
otp-version: '26.0.2'
54-
gleam-version: '1.4.1'
53+
otp-version: '27.0.0'
54+
gleam-version: '1.6.2'
5555
rebar3-version: '3'
5656
- name: Download gleam dependencies
5757
run: gleam deps download

.mise.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Runtimes used by the stack.
22
[tools]
3-
gleam = "1.4.1"
3+
gleam = "1.6.2"
44
erlang = "27"
55
node = "22"
66
deno = "latest"

apps/backend/gleam.toml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,33 @@ name = "backend"
22
version = "1.0.0"
33

44
[dependencies]
5-
aws4_request = ">= 0.1.1 and < 1.0.0"
5+
aws4_request = ">= 1.2.0 and < 2.0.0"
66
birl = "~> 1.6"
77
chomp = ">= 0.1.0 and < 1.0.0"
8-
cors_builder = ">= 2.0.0 and < 3.0.0"
8+
cors_builder = ">= 2.0.2 and < 3.0.0"
99
decipher = ">= 1.2.0 and < 2.0.0"
10+
envoy = ">= 1.0.2 and < 2.0.0"
1011
gleam_erlang = "~> 0.25"
1112
gleam_hexpm = "~> 1.0"
1213
gleam_http = "~> 3.6"
1314
gleam_httpc = ">= 2.2.0 and < 3.0.0"
14-
gleam_json = "~> 1.0"
15+
gleam_json = ">= 2.1.0 and < 3.0.0"
1516
gleam_otp = "~> 0.10"
1617
gleam_package_interface = ">= 1.0.0 and < 2.0.0"
17-
gleam_pgo = {path = "../../packages/pgo"}
18-
gleam_stdlib = "~> 0.34 or ~> 1.0"
18+
gleam_regexp = ">= 1.0.0 and < 2.0.0"
19+
gleam_stdlib = ">= 0.44.0 and < 1.0.0"
20+
gleam_yielder = ">= 1.1.0 and < 2.0.0"
1921
glexer = ">= 1.0.1 and < 2.0.0"
20-
mist = ">= 1.2.0 and < 2.0.0"
21-
pgo = "~> 0.14"
22+
interfaces = {path = "../../packages/interfaces"}
23+
mist = ">= 3.0.0 and < 4.0.0"
24+
pog = ">= 1.0.1 and < 2.0.0"
2225
prng = ">= 3.0.3 and < 4.0.0"
2326
radiate = ">= 0.4.0 and < 1.0.0"
2427
ranger = ">= 1.2.0 and < 2.0.0"
2528
simplifile = ">= 2.1.0 and < 3.0.0"
26-
tom = { path ="../../packages/tom" }
29+
tom = ">= 1.1.0 and < 2.0.0"
2730
verl = ">= 1.1.1 and < 2.0.0"
28-
wisp = ">= 1.1.0 and < 2.0.0"
31+
wisp = ">= 1.3.0 and < 2.0.0"
2932

3033
[dev-dependencies]
3134
gleeunit = "~> 1.0"

apps/backend/manifest.toml

Lines changed: 39 additions & 34 deletions
Large diffs are not rendered by default.

apps/backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
"backend:db:reset": "yarn backend:db:drop && yarn backend:db:init"
1010
},
1111
"dependencies": {
12-
"@chouqueth/gleam": "^1.3.2"
12+
"@chouqueth/gleam": "^1.6.2"
1313
}
1414
}

apps/backend/src/api/github.gleam

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import gleam/httpc
88
import gleam/json
99
import gleam/list
1010
import gleam/option.{type Option, Some}
11-
import gleam/regex
11+
import gleam/regexp
1212
import gleam/result
1313

1414
fn query(
@@ -17,32 +17,35 @@ fn query(
1717
variables: Option(json.Json),
1818
decoder: dynamic.Decoder(a),
1919
) {
20-
let body =
21-
json.object([
22-
#("query", json.string(query)),
23-
#("variables", json.nullable(variables, function.identity)),
24-
])
25-
use response <- result.try(
20+
use response <- result.try({
2621
request.new()
2722
|> request.set_header("authorization", "Bearer " <> token)
2823
|> request.set_header("user-agent", "gloogle / 1.0.0")
2924
|> request.set_method(http.Post)
3025
|> request.set_scheme(http.Https)
3126
|> request.set_host("api.github.com")
3227
|> request.set_path("/graphql")
33-
|> request.set_body(json.to_string(body))
28+
|> request.set_body(encode_body(query, variables))
3429
|> httpc.send()
35-
|> result.map_error(error.FetchError),
36-
)
30+
|> result.map_error(error.FetchError)
31+
})
3732

3833
response.body
3934
|> json.decode(using: decoder)
4035
|> result.map_error(error.JsonError)
4136
}
4237

38+
fn encode_body(query: String, variables: Option(json.Json)) -> String {
39+
json.object([
40+
#("query", json.string(query)),
41+
#("variables", json.nullable(variables, function.identity)),
42+
])
43+
|> json.to_string
44+
}
45+
4346
fn match_repository_name(repo_url: String) {
44-
let assert Ok(owner_name) = regex.from_string("https://github.com/(.+)/(.+)")
45-
regex.scan(with: owner_name, content: repo_url)
47+
let assert Ok(owner_name) = regexp.from_string("https://github.com/(.+)/(.+)")
48+
regexp.scan(with: owner_name, content: repo_url)
4649
|> list.first()
4750
|> result.replace_error(error.UnknownError(
4851
"No repository match for " <> repo_url,

apps/backend/src/api/hex_repo.gleam

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import aws/s3
12
import backend/error
23
import gleam/bit_array
34
import gleam/erlang/process
@@ -7,23 +8,22 @@ import gleam/httpc
78
import gleam/json
89
import gleam/package_interface
910
import gleam/result
10-
import s3
1111
import simplifile
1212
import tom
1313
import wisp
1414

15-
@external(erlang, "gloogle_hex_ffi", "get_home")
15+
@external(erlang, "backend_ffi", "get_home")
1616
pub fn get_home() -> Result(String, Nil)
1717

18-
@external(erlang, "gloogle_hex_ffi", "extract_tar")
18+
@external(erlang, "backend_ffi", "extract_tar")
1919
fn extract_tar(
2020
tarbin: BitArray,
2121
base_name: String,
2222
version: String,
2323
slug: String,
2424
) -> Result(#(String, String, String), Nil)
2525

26-
@external(erlang, "gloogle_hex_ffi", "remove_tar")
26+
@external(erlang, "backend_ffi", "remove_tar")
2727
fn remove_tar(slug: String) -> Nil
2828

2929
fn package_slug(name: String, version: String) {

apps/backend/src/s3.gleam renamed to apps/backend/src/aws/s3.gleam

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
import aws4_request
2-
import backend/config
3-
import birl
2+
import backend/context
43
import gleam/http
54
import gleam/http/request
65
import gleam/httpc
76
import gleam/option.{type Option, None, Some}
87
import gleam/result
98

109
fn request(url: String, method: http.Method, body: Option(BitArray)) {
11-
let date = birl.to_erlang_universal_datetime(birl.now())
12-
use bucket_uri <- result.try(config.bucket_uri())
13-
use #(access_key, secret_key) <- result.try(config.scaleway_keys())
10+
use bucket_uri <- result.try(context.bucket_uri())
11+
use #(access_key, secret_key) <- result.try(context.scaleway_keys())
1412
request.new()
1513
|> request.set_method(method)
1614
|> request.set_path(url)
1715
|> request.set_body(option.unwrap(body, <<>>))
1816
|> request.set_host(bucket_uri)
1917
|> request.set_scheme(http.Https)
2018
|> request.set_header("content-type", "application/octet-stream")
21-
|> aws4_request.sign(date, access_key, secret_key, "fr-par", "s3")
19+
|> sign(access_key, secret_key)
2220
|> httpc.send_bits()
23-
|> result.nil_error()
21+
|> result.replace_error(Nil)
22+
}
23+
24+
fn sign(request, access_key_id, secret_access_key) {
25+
aws4_request.signer(
26+
access_key_id:,
27+
secret_access_key:,
28+
region: "fr-par",
29+
service: "s3",
30+
)
31+
|> aws4_request.sign_bits(request)
2432
}
2533

2634
pub fn get(name: String) {

apps/backend/src/backend.gleam

Lines changed: 39 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,57 @@
1-
import backend/config
1+
import backend/context.{type Context, Context}
22
import backend/gleam/type_search/state as type_search
3-
import backend/postgres/postgres
43
import backend/router
4+
import backend/setup
5+
import backend/workers
6+
import envoy
57
import gleam/erlang/process
68
import gleam/function
9+
import gleam/int
10+
import gleam/option.{Some}
711
import gleam/otp/supervisor
12+
import gleam/result
813
import mist
9-
import periodic
10-
import setup
11-
import tasks/hex
12-
import tasks/popularity
13-
import tasks/ranking
14-
import tasks/timeseries
1514
import wisp
1615
import wisp/logger
1716
import wisp/wisp_mist
1817

1918
pub fn main() {
20-
wisp.configure_logger()
21-
22-
let secret_key_base = config.get_secret_key_base()
23-
let cnf = config.read_config()
24-
let ctx = postgres.connect(cnf)
19+
configure_logger()
20+
let assert Ok(ctx) = context.init()
21+
let assert Ok(ctx) = start_type_search_worker(ctx)
22+
let assert Ok(_) = start_http_server(ctx)
23+
let assert Ok(_) = start_periodic_workers(ctx)
24+
process.sleep_forever()
25+
}
2526

26-
logger.set_level(cnf.level)
27+
fn configure_logger() {
28+
let level = logger.read_level()
29+
wisp.configure_logger()
30+
logger.set_level(level)
2731
setup.radiate()
32+
}
2833

29-
let assert Ok(subject) = type_search.init(ctx.db)
30-
31-
let ctx = ctx |> config.add_type_search_subject(subject)
32-
33-
let assert Ok(_) =
34-
router.handle_request(_, ctx)
35-
|> wisp_mist.handler(secret_key_base)
36-
|> mist.new()
37-
|> mist.port(cnf.port)
38-
|> mist.start_http()
39-
40-
let assert Ok(_) = {
41-
use periodic_children <- supervisor.start()
42-
use periodic_children <- function.tap(periodic_children)
43-
let assert Ok(_) = {
44-
use children <- supervisor.start()
45-
// Every 10 seconds
46-
add_periodic_worker(periodic_children, waiting: 10 * 1000, do: fn() {
47-
hex.sync_new_gleam_releases(ctx, children)
48-
})
49-
// Every day
50-
add_periodic_worker(periodic_children, waiting: 86_400_000, do: fn() {
51-
ranking.compute_ranking(ctx)
52-
})
53-
// Every day
54-
add_periodic_worker(periodic_children, waiting: 86_400_000, do: fn() {
55-
popularity.compute_popularity(ctx)
56-
})
57-
// Every hour
58-
add_periodic_worker(periodic_children, waiting: 3600 * 1000, do: fn() {
59-
timeseries.store_timeseries(ctx)
60-
})
61-
}
62-
}
34+
fn start_type_search_worker(ctx: Context) {
35+
use subject <- result.map(type_search.init(ctx.db))
36+
Context(..ctx, type_search_subject: Some(subject))
37+
}
6338

64-
process.sleep_forever()
39+
fn start_http_server(ctx) {
40+
use port <- result.try(envoy.get("PORT"))
41+
use port <- result.map(int.parse(port))
42+
let secret_key_base = context.get_secret_key_base()
43+
router.handle_request(_, ctx)
44+
|> wisp_mist.handler(secret_key_base)
45+
|> mist.new()
46+
|> mist.port(port)
47+
|> mist.start_http()
6548
}
6649

67-
fn add_periodic_worker(children, waiting delay, do work) {
68-
use _ <- function.tap(children)
69-
supervisor.add(children, {
70-
use _ <- supervisor.worker()
71-
periodic.periodically(do: work, waiting: delay)
72-
})
50+
fn start_periodic_workers(ctx) {
51+
use children <- supervisor.start()
52+
use children <- function.tap(children)
53+
workers.sync_new_gleam_releases_ten_secondly(ctx, children)
54+
workers.compute_ranking_daily(ctx, children)
55+
workers.compute_popularity_daily(ctx, children)
56+
workers.store_timeseries_hourly(ctx, children)
7357
}

0 commit comments

Comments
 (0)