Current section
Files
Jump to
Current section
Files
src/olive.gleam
import gleam/erlang/process.{type Subject}
import gleam/list
import gleam/otp/actor
import gleam/string
import olive/cli
import olive/client_registry.{type ClientRegistry}
import olive/config
import olive/logging
import olive/proxy
import olive/server_run
import olive/watcher
/// Process is as follow:
/// - Start a client registry
/// - Start watcher, giving it a subject we will listen to.
/// - Every time watcher sends us a message:
/// - Reload server code
/// - Send reload message to clients
pub fn main() {
case cli.get_options() {
Error(Nil) -> Nil
Ok(options) -> {
let logger = logging.get_logger(options.log)
case config.read_config(logger, options) {
Error(error) -> logging.error(logger, error)
Ok(config) -> run_olive(config)
}
}
}
}
fn run_olive(config: config.Config) {
let clients = client_registry.start(config.logger)
let subject = process.new_subject()
case watcher.start(config, subject) {
Error(actor.InitTimeout) ->
logging.error(config.logger, "Watcher took too much time to initialize")
Error(actor.InitCrashed(_)) ->
logging.error(config.logger, "Watcher crashed!")
Error(actor.InitFailed(process.Abnormal(msg))) ->
logging.error(config.logger, msg)
Error(actor.InitFailed(process.Killed)) ->
logging.error(config.logger, "Watcher was killed before initialisation")
Error(actor.InitFailed(process.Normal)) ->
logging.error(
config.logger,
"Watcher shutdown before end of initialisation",
)
Ok(_) -> {
case server_run.start_server(config) {
Ok(_pid) -> {
let assert Ok(_) = proxy.start_http(config, clients)
listen_to_file_changes(config, subject, clients)
}
Error(reason) -> {
logging.error(
config.logger,
"Could not start your server:\n" <> reason,
)
}
}
}
}
}
fn listen_to_file_changes(
config: config.Config,
subject: Subject(watcher.Message),
clients: ClientRegistry,
) {
let msg = process.receive_forever(subject)
case msg {
watcher.FilesChanged(changes) -> {
case has_main_file(config, changes) {
True -> {
logging.warning(
config.logger,
"Main file changed. You need to restart olive for changes to be applied!",
)
}
False -> {
let changelog =
changes
|> list.map(fn(change) { change.file_name })
|> string.join("\n")
logging.debug(config.logger, "Files changed:\n" <> changelog)
let after_build = case needs_rebuild(changes) {
True -> server_run.reload_server_code(config)
False -> Ok(Nil)
}
case after_build {
Ok(_) -> {
client_registry.trigger(clients)
}
Error(msg) -> {
logging.error(config.logger, msg)
}
}
listen_to_file_changes(config, subject, clients)
}
}
}
}
}
fn has_main_file(config: config.Config, changes: List(watcher.Change)) {
let main_file = "src/" <> config.name <> ".gleam"
changes
|> list.any(fn(change) { string.ends_with(change.file_name, main_file) })
}
fn needs_rebuild(changes: List(watcher.Change)) {
changes
|> list.any(fn(change) {
case change {
watcher.SourceChange(..) -> True
watcher.PrivChange(..) -> False
}
})
}