Skip to content

Commit

Permalink
ios: add string accessor API (#1202)
Browse files Browse the repository at this point in the history
Description: iOS parallel to #1188
Risk Level: low
Testing: example app. Pending test with assertion filter.
Docs Changes: pending full API docs

Signed-off-by: Jose Nino <jnino@lyft.com>
Signed-off-by: JP Simard <jp@jpsim.com>
  • Loading branch information
junr03 authored and jpsim committed Nov 29, 2022
1 parent a5f4996 commit 6d70296
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 14 deletions.
1 change: 1 addition & 0 deletions mobile/examples/swift/hello_world/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ final class ViewController: UITableViewController {
// swiftlint:disable:next line_length
typedConfig: "{\"@type\":\"type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer\",\"max_request_bytes\":5242880}")
.setOnEngineRunning { NSLog("Envoy async internal setup completed") }
.addStringAccessor(name: "string_accessor", accessor: { return "DemoStringAccessor" })
.build()
self.streamClient = engine.streamClient()
self.pulseClient = engine.pulseClient()
Expand Down
4 changes: 2 additions & 2 deletions mobile/library/common/api/c_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
extern "C" { // function pointers
#endif

typedef envoy_data (*envoy_get_string_f)(void* context);
typedef envoy_data (*envoy_get_string_f)(const void* context);

#ifdef __cplusplus
} // function pointers
Expand All @@ -21,5 +21,5 @@ typedef envoy_data (*envoy_get_string_f)(void* context);
// types.
typedef struct {
envoy_get_string_f get_string;
void* context;
const void* context;
} envoy_string_accessor;
2 changes: 1 addition & 1 deletion mobile/library/common/api/external.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void registerApi(std::string name, void* api) { registry_[name] = api; }
// before any reads occur.
void* retrieveApi(std::string name) {
void* api = registry_[name];
ASSERT(api);
ASSERT(api, fmt::format("{} not registered", name));
return api;
}

Expand Down
4 changes: 2 additions & 2 deletions mobile/library/common/jni/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -654,9 +654,9 @@ static const void* jvm_http_filter_init(const void* context) {

// EnvoyStringAccessor

static envoy_data jvm_get_string(void* context) {
static envoy_data jvm_get_string(const void* context) {
JNIEnv* env = get_env();
jobject j_context = static_cast<jobject>(context);
jobject j_context = static_cast<jobject>(const_cast<void*>(context));
jclass jcls_JvmStringAccessorContext = env->GetObjectClass(j_context);
jmethodID jmid_getString =
env->GetMethodID(jcls_JvmStringAccessorContext, "getString", "()Ljava/nio/ByteBuffer;");
Expand Down
1 change: 1 addition & 0 deletions mobile/library/objective-c/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ objc_library(
"EnvoyHTTPStreamImpl.m",
"EnvoyNativeFilterConfig.m",
"EnvoyNetworkMonitor.m",
"EnvoyStringAccessor.m",
],
hdrs = [
"EnvoyEngine.h",
Expand Down
8 changes: 5 additions & 3 deletions mobile/library/objective-c/EnvoyConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ - (instancetype)initWithStatsDomain:(NSString *)statsDomain
appId:(NSString *)appId
virtualClusters:(NSString *)virtualClusters
nativeFilterChain:(NSArray<EnvoyNativeFilterConfig *> *)nativeFilterChain
platformFilterChain:
(NSArray<EnvoyHTTPFilterFactory *> *)httpPlatformFilterFactories {
platformFilterChain:(NSArray<EnvoyHTTPFilterFactory *> *)httpPlatformFilterFactories
stringAccessors:
(NSDictionary<NSString *, EnvoyStringAccessor *> *)stringAccessors {
self = [super init];
if (!self) {
return nil;
Expand All @@ -26,12 +27,13 @@ - (instancetype)initWithStatsDomain:(NSString *)statsDomain
self.dnsRefreshSeconds = dnsRefreshSeconds;
self.dnsFailureRefreshSecondsBase = dnsFailureRefreshSecondsBase;
self.dnsFailureRefreshSecondsMax = dnsFailureRefreshSecondsMax;
self.httpPlatformFilterFactories = httpPlatformFilterFactories;
self.statsFlushSeconds = statsFlushSeconds;
self.appVersion = appVersion;
self.appId = appId;
self.virtualClusters = virtualClusters;
self.nativeFilterChain = nativeFilterChain;
self.httpPlatformFilterFactories = httpPlatformFilterFactories;
self.stringAccessors = stringAccessors;
return self;
}

Expand Down
16 changes: 14 additions & 2 deletions mobile/library/objective-c/EnvoyEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ extern const int kEnvoyFilterResumeStatusResumeIteration;

@end

#pragma mark - EnvoyStringAccessor

@interface EnvoyStringAccessor : NSObject

@property (nonatomic, copy) NSString * (^getEnvoyString)();

- (instancetype)initWithBlock:(NSString * (^)())block;

@end

#pragma mark - EnvoyNativeFilterConfig

@interface EnvoyNativeFilterConfig : NSObject
Expand Down Expand Up @@ -252,6 +262,7 @@ extern const int kEnvoyFilterResumeStatusResumeIteration;
@property (nonatomic, strong) NSString *virtualClusters;
@property (nonatomic, strong) NSArray<EnvoyNativeFilterConfig *> *nativeFilterChain;
@property (nonatomic, strong) NSArray<EnvoyHTTPFilterFactory *> *httpPlatformFilterFactories;
@property (nonatomic, strong) NSDictionary<NSString *, EnvoyStringAccessor *> *stringAccessors;

/**
Create a new instance of the configuration.
Expand All @@ -266,8 +277,9 @@ extern const int kEnvoyFilterResumeStatusResumeIteration;
appId:(NSString *)appId
virtualClusters:(NSString *)virtualClusters
nativeFilterChain:(NSArray<EnvoyNativeFilterConfig *> *)nativeFilterChain
platformFilterChain:
(NSArray<EnvoyHTTPFilterFactory *> *)httpPlatformFilterFactories;
platformFilterChain:(NSArray<EnvoyHTTPFilterFactory *> *)httpPlatformFilterFactories
stringAccessors:
(NSDictionary<NSString *, EnvoyStringAccessor *> *)stringAccessors;

/**
Resolves the provided configuration template using properties on this configuration.
Expand Down
25 changes: 25 additions & 0 deletions mobile/library/objective-c/EnvoyEngineImpl.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#import "library/objective-c/EnvoyBridgeUtility.h"
#import "library/objective-c/EnvoyHTTPFilterCallbacksImpl.h"

#include "library/common/api/c_types.h"

#import "library/common/main_interface.h"
#import "library/common/types/c_types.h"

Expand Down Expand Up @@ -286,6 +288,11 @@ static void ios_http_filter_release(const void *context) {
return;
}

static envoy_data ios_get_string(const void *context) {
EnvoyStringAccessor *accessor = (__bridge EnvoyStringAccessor *)context;
return toManagedNativeString(accessor.getEnvoyString());
}

@implementation EnvoyEngineImpl {
envoy_engine_t _engineHandle;
}
Expand Down Expand Up @@ -330,6 +337,16 @@ - (int)registerFilterFactory:(EnvoyHTTPFilterFactory *)filterFactory {
return kEnvoySuccess;
}

- (int)registerStringAccessor:(NSString *)name accessor:(EnvoyStringAccessor *)accessor {
// TODO(goaway): Everything here leaks, but it's all be tied to the life of the engine.
// This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332
envoy_string_accessor *accessorStruct = safe_malloc(sizeof(envoy_string_accessor));
accessorStruct->get_string = ios_get_string;
accessorStruct->context = CFBridgingRetain(accessor);

return register_platform_api(name.UTF8String, accessorStruct);
}

- (int)runWithConfig:(EnvoyConfiguration *)config
logLevel:(NSString *)logLevel
onEngineRunning:(nullable void (^)())onEngineRunning {
Expand All @@ -343,6 +360,10 @@ - (int)runWithConfig:(EnvoyConfiguration *)config
[self registerFilterFactory:filterFactory];
}

for (NSString *name in config.stringAccessors) {
[self registerStringAccessor:name accessor:config.stringAccessors[name]];
}

return [self runWithConfigYAML:resolvedYAML logLevel:logLevel onEngineRunning:onEngineRunning];
}

Expand All @@ -359,6 +380,10 @@ - (int)runWithTemplate:(NSString *)yaml
[self registerFilterFactory:filterFactory];
}

for (NSString *name in config.stringAccessors) {
[self registerStringAccessor:name accessor:config.stringAccessors[name]];
}

return [self runWithConfigYAML:resolvedYAML logLevel:logLevel onEngineRunning:onEngineRunning];
}

Expand Down
15 changes: 15 additions & 0 deletions mobile/library/objective-c/EnvoyStringAccessor.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import "library/objective-c/EnvoyEngine.h"

@implementation EnvoyStringAccessor

- (instancetype)initWithBlock:(NSString * (^)())block {
self = [super init];
if (!self) {
return nil;
}

self.getEnvoyString = block;
return self;
}

@end
19 changes: 17 additions & 2 deletions mobile/library/swift/src/EngineBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ public final class EngineBuilder: NSObject {
private var statsFlushSeconds: UInt32 = 60
private var appVersion: String = "unspecified"
private var appId: String = "unspecified"
private var platformFilterChain: [EnvoyHTTPFilterFactory] = []
private var virtualClusters: String = "[]"
private var onEngineRunning: (() -> Void)?
private var nativeFilterChain: [EnvoyNativeFilterConfig] = []
private var platformFilterChain: [EnvoyHTTPFilterFactory] = []
private var stringAccessors: [String: EnvoyStringAccessor] = [:]

// MARK: - Public

Expand Down Expand Up @@ -142,6 +143,19 @@ public final class EngineBuilder: NSObject {
return self
}

/// Add a string accessor to this Envoy Client.
///
/// - parameter name: the name of the accessor.
/// - parameter accessor: lambda to access a string from the platform layer.
///
/// - returns this builder.
@discardableResult
public func addStringAccessor(name: String,
accessor: @escaping () -> String) -> EngineBuilder {
self.stringAccessors[name] = EnvoyStringAccessor(block: accessor)
return self
}

/// Set a closure to be called when the engine finishes its async startup and begins running.
///
/// - parameter closure: The closure to be called.
Expand Down Expand Up @@ -202,7 +216,8 @@ public final class EngineBuilder: NSObject {
appId: self.appId,
virtualClusters: self.virtualClusters,
nativeFilterChain: self.nativeFilterChain,
platformFilterChain: self.platformFilterChain)
platformFilterChain: self.platformFilterChain,
stringAccessors: self.stringAccessors)

switch self.base {
case .custom(let yaml):
Expand Down
20 changes: 18 additions & 2 deletions mobile/library/swift/test/EngineBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ final class EngineBuilderTests: XCTestCase {
self.waitForExpectations(timeout: 0.01)
}

func testAddingStringAccessorToConfigurationWhenRunningEnvoy() throws {
let expectation = self.expectation(description: "Run called with expected data")
MockEnvoyEngine.onRunWithConfig = { config, _ in
XCTAssertEqual("hello", config.stringAccessors["name"]?.getEnvoyString())
expectation.fulfill()
}

_ = try EngineBuilder()
.addEngineType(MockEnvoyEngine.self)
.addStringAccessor(name: "name", accessor: { "hello" })
.build()
self.waitForExpectations(timeout: 0.01)
}

func testResolvesYAMLWithIndividuallySetValues() throws {
let filterFactory = EnvoyHTTPFilterFactory(filterName: "TestFilter", factory: TestFilter.init)
let config = EnvoyConfiguration(statsDomain: "stats.envoyproxy.io",
Expand All @@ -214,7 +228,8 @@ final class EngineBuilderTests: XCTestCase {
[EnvoyNativeFilterConfig(name: "filter_name",
typedConfig: "test_config"),
],
platformFilterChain: [filterFactory])
platformFilterChain: [filterFactory],
stringAccessors: [:])
let resolvedYAML = try XCTUnwrap(config.resolveTemplate(kMockTemplate))
XCTAssertTrue(resolvedYAML.contains("stats_domain: stats.envoyproxy.io"))
XCTAssertTrue(resolvedYAML.contains("connect_timeout: 200s"))
Expand Down Expand Up @@ -242,7 +257,8 @@ final class EngineBuilderTests: XCTestCase {
appId: "com.envoymobile.ios",
virtualClusters: "[test]",
nativeFilterChain: [],
platformFilterChain: [])
platformFilterChain: [],
stringAccessors: [:])
XCTAssertNil(config.resolveTemplate("{{ missing }}"))
}
}

0 comments on commit 6d70296

Please sign in to comment.