Skip to content

Commit

Permalink
chore(runtime): Read configuration from disk, if present (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnys1 authored Oct 9, 2024
1 parent 7935262 commit 20a6fb9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 8 deletions.
20 changes: 18 additions & 2 deletions packages/celest/lib/src/config/env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ sealed class ConfigurationValue implements ContextKey<String> {

@override
String? read(Context context) {
return context.platform.environment[name];
return context[this] as String? ?? context.platform.environment[name];
}

@override
void set(Context context, String? value) {
throw UnsupportedError('Cannot set a configuration value at runtime.');
context[this] = value;
}
}

Expand All @@ -40,6 +40,14 @@ final class env extends ConfigurationValue {

@override
String toString() => 'env($name)';

@override
bool operator ==(Object other) {
return identical(this, other) || other is env && other.name == name;
}

@override
int get hashCode => Object.hash(env, name);
}

final class _staticEnv extends env {
Expand All @@ -60,4 +68,12 @@ final class secret extends ConfigurationValue {

@override
String toString() => 'secret($name)';

@override
bool operator ==(Object other) {
return identical(this, other) || other is secret && other.name == name;
}

@override
int get hashCode => Object.hash(secret, name);
}
7 changes: 1 addition & 6 deletions packages/celest/lib/src/core/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,7 @@ final class Context {
Traceparent get currentTrace => expect(ContextKey.currentTrace);

/// The Celest [Environment] of the running service.
Environment get environment {
return switch (get(env.environment)) {
final env? => Environment(env),
_ => throw StateError('No environment set in context'),
};
}
Environment get environment => expect(env.environment) as Environment;

/// The HTTP client for the current context.
http.Client get httpClient =>
Expand Down
67 changes: 67 additions & 0 deletions packages/celest/lib/src/runtime/http/environment.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import 'dart:convert';
import 'dart:io';

import 'package:celest/src/config/env.dart';
import 'package:celest/src/core/context.dart';
import 'package:celest_core/_internal.dart';
import 'package:logging/logging.dart';

/// Configures the environment in which Celest is running.
Future<void> configureEnvironment() async {
final script = Platform.script;
final configUri = script.resolve('./config.json');
if (!FileSystemEntity.isFileSync(configUri.toFilePath())) {
if (kReleaseMode) {
Logger.root.finer(
'No config.json file found. Skipping environment configuration.',
);
}
return;
}

final configFile = await File.fromUri(configUri)
.readAsString()
.onError((e, _) => throw StateError('Failed to load config.json: $e'));

final configJson = jsonDecode(configFile);
if (configJson is! Map<String, Object?>) {
throw FormatException(
'Invalid config.json: $configJson. '
'Expected Map<String, Object?>, got ${configJson.runtimeType}',
);
}
final environmentVariables = configJson['environmentVariables'];
if (environmentVariables is! Map<String, Object?>) {
throw FormatException(
'Invalid "environmentVariables" in config.json: $environmentVariables. '
'Expected Map<String, String>, got ${environmentVariables.runtimeType}',
);
}
final secrets = configJson['secrets'];
if (secrets is! Map<String, Object?>) {
throw FormatException(
'Invalid "secrets" in config.json: $secrets. '
'Expected Map<String, String>, got ${secrets.runtimeType}',
);
}

for (final MapEntry(key: name, :value) in environmentVariables.entries) {
if (value is! String) {
throw FormatException(
'Invalid value for environment variable "$name" in config.json: $value. '
'Expected String, got ${value.runtimeType}',
);
}
Context.root.put(env(name), value);
}

for (final MapEntry(key: name, :value) in secrets.entries) {
if (value is! String) {
throw FormatException(
'Invalid value for secret "$name" in config.json: $value. '
'Expected String, got ${value.runtimeType}',
);
}
Context.root.put(secret(name), value);
}
}
2 changes: 2 additions & 0 deletions packages/celest/lib/src/runtime/serve.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:async/async.dart';
import 'package:celest/celest.dart';
import 'package:celest/src/runtime/gcp/gcp.dart';
import 'package:celest/src/runtime/http/cloud_middleware.dart';
import 'package:celest/src/runtime/http/environment.dart';
import 'package:celest/src/runtime/http/logging.dart';
import 'package:celest/src/runtime/http/middleware.dart';
import 'package:celest/src/runtime/json_utils.dart';
Expand Down Expand Up @@ -35,6 +36,7 @@ Future<void> serve({
required Map<String, CloudFunctionTarget> targets,
}) async {
configureLogging();
await configureEnvironment();
final projectId = await googleCloudProject();
if (projectId != null) {
Context.root.put(googleCloudProjectKey, projectId);
Expand Down

0 comments on commit 20a6fb9

Please sign in to comment.