├── .github └── pull_request_template.md ├── .gitignore ├── CHANGES.txt ├── CONTRIBUTORS-GUIDE.md ├── LICENSE.txt ├── README.md ├── Split.io.sln ├── Splitio-net-core-tests ├── Integration Tests │ ├── JSONFileClientTests.cs │ ├── LocalhostClientTests.cs │ ├── RedisAdapterTests.cs │ ├── RedisClientTests.cs │ ├── SdkApiClientTests.cs │ ├── SelfRefreshingSegmentFetcherTests.cs │ ├── SelfRefreshingSplitClientTests.cs │ ├── SelfRefreshingSplitFetcherTests.cs │ └── SplitSdkApiClientTests.cs ├── Resources │ ├── SplitsHelper.cs │ ├── legacy-sample-data-non-alpha-numeric.csv │ ├── legacy-sample-data.csv │ ├── murmur3-64-128.csv │ ├── murmur3-sample-data-non-alpha-numeric-v2.csv │ ├── murmur3-sample-data-non-alpha-numeric.csv │ ├── murmur3-sample-data-v2.csv │ ├── murmur3-sample-data.csv │ ├── regex.txt │ ├── segment_payed.json │ ├── split.yaml │ ├── split.yml │ ├── splits_staging.json │ ├── splits_staging_2.json │ ├── splits_staging_3.json │ ├── splits_staging_4.json │ ├── splits_staging_5.json │ ├── splits_staging_6.json │ ├── splits_staging_7.json │ └── test.splits ├── Splitio-net-core-tests.csproj └── Unit Tests │ ├── Cache │ ├── InMemoryMetricsCacheTests.cs │ ├── InMemorySimpleCacheTests.cs │ ├── Lru │ │ ├── CacheTests.cs │ │ ├── EnumeratorTests.cs │ │ ├── IDictionaryTests.cs │ │ ├── NodeTests.cs │ │ └── TestData.cs │ ├── RedisCacheBaseTests.cs │ ├── RedisImpressionCacheTests.cs │ ├── RedisMetricsCacheTests.cs │ ├── RedisSegmentCacheTests.cs │ ├── RedisSplitCacheTests.cs │ ├── SegmentCacheTests.cs │ └── SplitCacheTests.cs │ ├── Client │ ├── LocalhostClientForTesting.cs │ ├── LocalhostClientUnitTests.cs │ ├── SdkReadinessGatesUnitTests.cs │ ├── SplitClientForTesting.cs │ ├── SplitClientUnitTests.cs │ ├── SplitFactoryUnitTests.cs │ └── SplitManagerUnitTests.cs │ ├── Common │ ├── AuthApiClientTests.cs │ ├── PushManagerTests.cs │ ├── SyncManagerTests.cs │ └── SynchronizerTests.cs │ ├── CommonLibraries │ └── TypeConverterUnitTests.cs │ ├── Evaluator │ └── EvaluatorTests.cs │ ├── EventSource │ ├── NotificationManagerKeeperTests.cs │ ├── NotificationParserTests.cs │ ├── NotificationPorcessorTests.cs │ ├── SSEHandlerTests.cs │ └── Workers │ │ ├── SegmentsWorkerTests.cs │ │ └── SplitsWorkerTests.cs │ ├── Events │ ├── EventsLogUnitTests.cs │ └── RedisEventsLogUnitTests.cs │ ├── Impressions │ ├── ImpressionHasherTests.cs │ ├── ImpressionsCountSenderTests.cs │ ├── ImpressionsCounterTests.cs │ ├── ImpressionsHelperTest.cs │ ├── ImpressionsLogUnitTests.cs │ ├── ImpressionsManagerTests.cs │ ├── ImpressionsObserverTests.cs │ ├── RedisImpressionsLogUnitTests.cs │ └── TreatmentSdkApiClientTests.cs │ ├── InputValidation │ ├── ApiKeyValidatorTests.cs │ ├── EventPropertiesValidatorTests.cs │ ├── EventTypeValidatorTests.cs │ ├── KeyValidatorTests.cs │ ├── SplitNameValidatorTests.cs │ └── TrafficTypeValidatorTests.cs │ ├── Matchers │ ├── AllKeysMatcherTests.cs │ ├── AttributeMatcherTests.cs │ ├── BetweenMatcherTests.cs │ ├── CombiningMatcherTests.cs │ ├── ContainsAllOfSetMatcherTests.cs │ ├── ContainsAnyOfSetMatcherTests.cs │ ├── ContainsStringMatcherTests.cs │ ├── DependencyMatcherTests.cs │ ├── EndsWithMatcherTests.cs │ ├── EqualToBooleanMatcherTests.cs │ ├── EqualToMatcherTests.cs │ ├── EqualsToSetMatcherTests.cs │ ├── GreaterOrEqualToMatcherTests.cs │ ├── LessOrEqualToMatcherTests.cs │ ├── MatchesStringMatcherTests.cs │ ├── PartOfSetMatcherTests.cs │ ├── SplitParserUnitTests.cs │ ├── StartsWithMatcherTests.cs │ ├── UserDefinedSegmentMatcherTests.cs │ └── WhitelistMatcherTests.cs │ ├── Metrics │ ├── AsyncMetricsLogUnitTests.cs │ ├── BinarySearchLatencyTrackerTests.cs │ ├── InMemoryMetricsLogUnitTests.cs │ └── RedisMetricsLogUnitTests.cs │ ├── SegmentFetcher │ ├── ApiSegmentChangeFetcherUnitTests.cs │ ├── SelfRefreshingSegmentFetcherUnitTests.cs │ └── SelfRefreshingSegmentUnitTests.cs │ ├── Shared │ ├── ConfigServiceTests.cs │ └── FactoryInstantiationsServiceTests.cs │ ├── SplitFetcher │ └── ApiSplitChangeFetcherTests.cs │ └── Splitter │ └── SplitterTests.cs ├── Splitio-net-core.Integration-tests ├── BaseIntegrationTests.cs ├── EventSource │ └── EventSourceClientTests.cs ├── HttpClientMock.cs ├── InMemoryTests.cs ├── PushClientTests.cs ├── RedisTests.cs ├── Resources │ ├── EventBackend.cs │ ├── IntegrationTestsImpressionListener.cs │ ├── KeyImpressionBackend.cs │ ├── StatusCodeEnum.cs │ ├── split_changes.json │ ├── split_changes_1.json │ ├── split_segment1.json │ ├── split_segment2.json │ ├── split_segment3.json │ ├── split_segment4.json │ ├── split_segment4_empty.json │ ├── split_segment4_updated.json │ ├── split_segment4_updated_empty.json │ ├── splits_push.json │ ├── splits_push2.json │ ├── splits_push3.json │ └── splits_push4.json └── Splitio-net-core.Integration-tests.csproj ├── Splitio-net-core.Redis ├── Services │ ├── Cache │ │ ├── Classes │ │ │ ├── RedisAdapter.cs │ │ │ ├── RedisCacheBase.cs │ │ │ ├── RedisEventsCache.cs │ │ │ ├── RedisImpressionsCache.cs │ │ │ ├── RedisMetricsCache.cs │ │ │ ├── RedisSegmentCache.cs │ │ │ └── RedisSplitCache.cs │ │ └── Interfaces │ │ │ └── IRedisAdapter.cs │ ├── Client │ │ └── Classes │ │ │ └── RedisClient.cs │ ├── Domain │ │ └── RedisConfig.cs │ ├── Events │ │ └── Classes │ │ │ └── RedisEventsLog.cs │ ├── Impressions │ │ └── Classes │ │ │ └── RedisImpressionLog.cs │ ├── Metrics │ │ └── Classes │ │ │ └── RedisMetricsLog.cs │ ├── Parsing │ │ └── Classes │ │ │ └── RedisSplitParser.cs │ └── Shared │ │ └── RedisBlockUntilReadyService.cs ├── Splitio.Redis.csproj └── SplitioRedis.snk ├── Splitio.TestSupport ├── README.md ├── Samples │ └── SampleTest.cs ├── SplitClientForTest.cs ├── SplitScenario.cs ├── SplitSuite.cs ├── SplitTest.cs └── Splitio-net-core.TestSupport.csproj ├── appveyor.yml ├── lib └── MurmurHash-net-core.dll ├── sonar-scanner.bat └── src └── Splitio-net-core ├── CommonLibraries ├── CurrentTimeHelper.cs ├── HTTPHeader.cs ├── HTTPResult.cs ├── ISdkApiClient.cs ├── PeriodicTaskFactory.cs ├── SdkApiClient.cs └── TypeConverter.cs ├── Domain ├── AdapterType.cs ├── AlgorithmEnum.cs ├── AttributeMatcher.cs ├── AuthenticationResponse.cs ├── BaseConfig.cs ├── BetweenData.cs ├── CacheAdapterConfigurationOptions.cs ├── CombinerEnum.cs ├── CombiningMatcher.cs ├── ConditionDefinition.cs ├── ConditionType.cs ├── ConditionWithLogic.cs ├── ConfigurationOptions.cs ├── Constans.cs ├── DataTypeEnum.cs ├── DependencyData.cs ├── Event.cs ├── EventValidatorResult.cs ├── ImpressionsMode.cs ├── Key.cs ├── KeyImpression.cs ├── KeySelector.cs ├── Labels.cs ├── LightSplit.cs ├── MatcherDefinition.cs ├── MatcherGroupDefinition.cs ├── MatcherTypeEnum.cs ├── Mode.cs ├── MultipleEvaluatorResult.cs ├── Operations.cs ├── ParsedSplit.cs ├── PartitionDefinition.cs ├── ReadConfigData.cs ├── Segment.cs ├── SegmentChange.cs ├── SelfRefreshingConfig.cs ├── Split.cs ├── SplitBase.cs ├── SplitChange.cs ├── SplitResult.cs ├── StatusEnum.cs ├── TreatmentResult.cs ├── UnaryNumericData.cs ├── UserDefinedSegmentData.cs ├── ValidatorResult.cs ├── WhiteListData.cs └── WrappedEvent.cs ├── Properties └── AssemblyInfo.cs ├── Services ├── Cache │ ├── Classes │ │ ├── InMemoryMetricsCache.cs │ │ ├── InMemoryReadinessGatesCache.cs │ │ ├── InMemorySegmentCache.cs │ │ └── InMemorySplitCache.cs │ ├── Interfaces │ │ ├── IMetricsCache.cs │ │ ├── IReadinessGatesCache.cs │ │ ├── ISegmentCache.cs │ │ └── ISplitCache.cs │ └── Lru │ │ ├── CacheEnumerator.cs │ │ ├── LruCache.cs │ │ └── Node.cs ├── Client │ ├── Classes │ │ ├── JSONFileClient.cs │ │ ├── LocalhostClient.cs │ │ ├── SelfRefreshingClient.cs │ │ ├── SplitClient.cs │ │ ├── SplitFactory.cs │ │ └── SplitManager.cs │ └── Interfaces │ │ ├── ISplitClient.cs │ │ ├── ISplitFactory.cs │ │ └── ISplitManager.cs ├── Common │ ├── AuthApiClient.cs │ ├── BackOff.cs │ ├── IAuthApiClient.cs │ ├── IBackOff.cs │ ├── IPushManager.cs │ ├── ISplitioHttpClient.cs │ ├── ISyncManager.cs │ ├── ISynchronizer.cs │ ├── PushManager.cs │ ├── SplitioHttpClient.cs │ ├── SyncManager.cs │ └── Synchronizer.cs ├── EngineEvaluator │ ├── ISplitter.cs │ └── Splitter.cs ├── Evaluator │ ├── Evaluator.cs │ └── IEvaluator.cs ├── EventSource │ ├── EventReceivedEventArgs.cs │ ├── EventSourceClient.cs │ ├── FeedbackEventArgs.cs │ ├── IEventSourceClient.cs │ ├── INotificationManagerKeeper.cs │ ├── INotificationParser.cs │ ├── INotificationProcessor.cs │ ├── ISSEHandler.cs │ ├── Notification.cs │ ├── NotificationManagerKeeper.cs │ ├── NotificationParser.cs │ ├── NotificationProcessor.cs │ ├── ReadStreamException.cs │ ├── SSEClientActions.cs │ ├── SSEHandler.cs │ └── Workers │ │ ├── ISegmentsWorker.cs │ │ ├── ISplitsWorker.cs │ │ ├── IWorker.cs │ │ ├── SegmentQueueDto.cs │ │ ├── SegmentsWorker.cs │ │ └── SplitsWorker.cs ├── Events │ ├── Classes │ │ ├── EventSdkApiClient.cs │ │ └── EventsLog.cs │ └── Interfaces │ │ ├── IEventSdkApiClient.cs │ │ └── IEventsLog.cs ├── Impressions │ ├── Classes │ │ ├── ImpressionHasher.cs │ │ ├── ImpressionsCountSender.cs │ │ ├── ImpressionsCounter.cs │ │ ├── ImpressionsHelper.cs │ │ ├── ImpressionsLog.cs │ │ ├── ImpressionsManager.cs │ │ ├── ImpressionsObserver.cs │ │ └── TreatmentSdkApiClient.cs │ └── Interfaces │ │ ├── IImpressionHasher.cs │ │ ├── IImpressionListener.cs │ │ ├── IImpressionsCountSender.cs │ │ ├── IImpressionsCounter.cs │ │ ├── IImpressionsLog.cs │ │ ├── IImpressionsManager.cs │ │ ├── IImpressionsObserver.cs │ │ └── ITreatmentSdkApiClient.cs ├── InputValidation │ ├── Classes │ │ ├── ApiKeyValidator.cs │ │ ├── EventPropertiesValidator.cs │ │ ├── EventTypeValidator.cs │ │ ├── KeyValidator.cs │ │ ├── SplitNameValidator.cs │ │ └── TrafficTypeValidator.cs │ └── Interfaces │ │ ├── IApiKeyValidator.cs │ │ ├── IEventPropertiesValidator.cs │ │ ├── IEventTypeValidator.cs │ │ ├── IKeyValidator.cs │ │ ├── ISplitNameValidator.cs │ │ └── ITrafficTypeValidator.cs ├── Logger │ ├── CommonLogging.cs │ ├── ISplitLogger.cs │ ├── MicrosoftExtensionsLogging.cs │ └── SplitLoggerFactoryExtensions.cs ├── Metrics │ ├── Classes │ │ ├── AsyncMetricsLog.cs │ │ ├── BinarySearchLatencyTracker.cs │ │ ├── Counter.cs │ │ ├── InMemoryMetricsLog.cs │ │ └── MetricsSdkApiClient.cs │ └── Interfaces │ │ ├── ILatencyTracker.cs │ │ ├── IMetricsLog.cs │ │ └── IMetricsSdkApiClient.cs ├── Parsing │ ├── Classes │ │ ├── AllKeysMatcher.cs │ │ ├── BaseMatcher.cs │ │ ├── BetweenMatcher.cs │ │ ├── CompareMatcher.cs │ │ ├── ContainsAllOfSetMatcher.cs │ │ ├── ContainsAnyOfSetMatcher.cs │ │ ├── ContainsStringMatcher.cs │ │ ├── DependencyMatcher.cs │ │ ├── EndsWithMatcher.cs │ │ ├── EqualToBooleanMatcher.cs │ │ ├── EqualToMatcher.cs │ │ ├── EqualToSetMatcher.cs │ │ ├── GreaterOrEqualToMatcher.cs │ │ ├── InMemorySplitParser.cs │ │ ├── LessOrEqualToMatcher.cs │ │ ├── MatchesStringMatcher.cs │ │ ├── PartOfSetMatcher.cs │ │ ├── SplitParser.cs │ │ ├── StartsWithMatcher.cs │ │ ├── UserDefinedSegmentMatcher.cs │ │ └── WhitelistMatcher.cs │ └── Interfaces │ │ ├── IMatcher.cs │ │ └── ISplitParser.cs ├── SegmentFetcher │ ├── Classes │ │ ├── ApiSegmentChangeFetcher.cs │ │ ├── JSONFileSegmentFetcher.cs │ │ ├── SegmentChangeFetcher.cs │ │ ├── SegmentFetcher.cs │ │ ├── SegmentSdkApiClient.cs │ │ ├── SegmentTaskQueue.cs │ │ ├── SegmentTaskWorker.cs │ │ ├── SelfRefreshingSegment.cs │ │ └── SelfRefreshingSegmentFetcher.cs │ └── Interfaces │ │ ├── ISegment.cs │ │ ├── ISegmentChangeFetcher.cs │ │ ├── ISegmentFetcher.cs │ │ ├── ISegmentSdkApiClient.cs │ │ ├── ISegmentTaskQueue.cs │ │ ├── ISelfRefreshingSegment.cs │ │ └── ISelfRefreshingSegmentFetcher.cs ├── Shared │ ├── Classes │ │ ├── AbstractLocalhostFileService.cs │ │ ├── BlockingQueue.cs │ │ ├── ConfigService.cs │ │ ├── FactoryInstantiationsService.cs │ │ ├── InMemorySimpleCache.cs │ │ ├── LocalhostFileService.cs │ │ ├── NoopBlockUntilReadyService.cs │ │ ├── SelfRefreshingBlockUntilReadyService.cs │ │ ├── WrapperAdapter.cs │ │ └── YamlLocalhostFileService.cs │ └── Interfaces │ │ ├── IBlockUntilReadyService.cs │ │ ├── IConfigService.cs │ │ ├── IFactoryInstantiationsService.cs │ │ ├── ILocalhostFileService.cs │ │ ├── ISimpleCache.cs │ │ ├── ISimpleProducerCache.cs │ │ └── IWrapperAdapter.cs └── SplitFetcher │ ├── Classes │ ├── ApiSplitChangeFetcher.cs │ ├── JSONFileSplitChangeFetcher.cs │ ├── SelfRefreshingSplitFetcher.cs │ ├── SplitChangeFetcher.cs │ └── SplitSdkApiClient.cs │ └── Interfaces │ ├── ISplitChangeFetcher.cs │ ├── ISplitFetcher.cs │ └── ISplitSdkApiClient.cs ├── Splitio.csproj ├── Splitio.csproj.user └── Splitio.snk /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # .NET SDK 2 | 3 | ## What did you accomplish? 4 | 5 | ## How do we test the changes introduced in this PR? 6 | 7 | ## Extra Notes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/Splitio-net-core/bin/Debug/netstandard1.6/* 2 | src/Splitio-net-core/obj/* 3 | TestResults/* 4 | .vs/config/applicationhost.config 5 | .vs/restore.dg 6 | .vs/Split.io-net-core/v14/.suo 7 | packages/* 8 | SplitioTests/bin/* 9 | SplitioTests/obj/* 10 | src/Splitio-net-core/bin/* 11 | .vs/Split.io-net-core/v15/.suo 12 | Splitio-net-core-tests/bin/* 13 | Splitio-net-core-tests/obj/* 14 | Splitio.TestSupport/bin 15 | Splitio.TestSupport/obj 16 | Splitio-net-core.Redis/obj 17 | Splitio-net-core.Redis/bin/ 18 | .vs/Split.io-net-core/v15/Server/sqlite3/storage.ide-wal 19 | .vs/Split.io-net-core/v15/Server/sqlite3/storage.ide-shm 20 | .vs/Split.io-net-core/v15/Server/sqlite3/storage.ide 21 | .vs/Split.io-net-core/v15/Server/sqlite3/db.lock 22 | /Splitio-net-core-tests/TestResults 23 | /Splitio-net-frameworks-tests/bin/Debug 24 | /Splitio-net-frameworks-tests/obj/Debug 25 | /Splitio-net-frameworks-tests/Splitio-net-frameworks-tests.csproj.user 26 | /.vs 27 | *.user 28 | Splitio-net-frameworks-tests/bin/ 29 | Splitio-net-frameworks-tests/obj/ 30 | /Splitio-net-core.Integration-tests/bin 31 | /Splitio-net-core.Integration-tests/obj 32 | -------------------------------------------------------------------------------- /CONTRIBUTORS-GUIDE.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Split .NET SDK 2 | 3 | Split SDK is an open source project and we welcome feedback and contribution. The information below describes how to build the project with your changes, run the tests, and send the Pull Request(PR). 4 | 5 | ## Development 6 | 7 | ### Development process 8 | 9 | 1. Fork the repository and create a topic branch from `development` branch. Please use a descriptive name for your branch. 10 | 2. While developing, use descriptive messages in your commits. Avoid short or meaningless sentences like "fix bug". 11 | 3. Make sure to add tests for both positive and negative cases. 12 | 4. Run the build and make sure it runs with no errors. 13 | 5. Run all tests and make sure there are no failures. 14 | 6. `git push` your changes to GitHub within your topic branch. 15 | 7. Open a Pull Request(PR) from your forked repo and into the `development` branch of the original repository. 16 | 8. When creating your PR, please fill out all the fields of the PR template, as applicable, for the project. 17 | 9. Check for conflicts once the pull request is created to make sure your PR can be merged cleanly into `development`. 18 | 10. Keep an eye out for any feedback or comments from Split's SDK team. 19 | 20 | ### Running tests 21 | You can execute the following commands in .net-core-client folder to run the tests: 22 | - dotnet test .\Splitio-net-core-tests\ 23 | - dotnet test .\Splitio-net-core.Integration-tests\ 24 | 25 | # Contact 26 | 27 | If you have any other questions or need to contact us directly in a private manner send us a note at sdks@split.io -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2021 Split Software, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Integration Tests/SplitSdkApiClientTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Splitio.CommonLibraries; 3 | using Splitio.Services.SplitFetcher.Classes; 4 | using System.Threading.Tasks; 5 | 6 | namespace Splitio_Tests.Integration_Tests 7 | { 8 | [TestClass] 9 | public class SplitSdkApiClientTests 10 | { 11 | [TestMethod] 12 | [Ignore] 13 | public async Task ExecuteFetchSplitChangesSuccessful() 14 | { 15 | //Arrange 16 | var baseUrl = "http://sdk-aws-staging.split.io/api/"; 17 | var httpHeader = new HTTPHeader() 18 | { 19 | authorizationApiKey = "///PUT API KEY HERE///", 20 | splitSDKMachineIP = "1.0.0.0", 21 | splitSDKMachineName = "localhost", 22 | splitSDKVersion = "net-0.0.0", 23 | splitSDKSpecVersion = "1.2", 24 | }; 25 | var SplitSdkApiClient = new SplitSdkApiClient(httpHeader, baseUrl, 10000, 10000); 26 | 27 | //Act 28 | var result = await SplitSdkApiClient.FetchSplitChanges(-1); 29 | 30 | //Assert 31 | Assert.IsTrue(result.Contains("splits")); 32 | } 33 | 34 | [TestMethod] 35 | public async Task ExecuteGetShouldReturnEmptyIfNotAuthorized() 36 | { 37 | //Arrange 38 | var baseUrl = "https://sdk.aws.staging.split.io/api"; 39 | var httpHeader = new HTTPHeader() 40 | { 41 | splitSDKMachineIP = "1.0.0.0", 42 | splitSDKMachineName = "localhost", 43 | splitSDKVersion = "net-0.0.0", 44 | splitSDKSpecVersion = "1.2" 45 | }; 46 | var SplitSdkApiClient = new SplitSdkApiClient(httpHeader, baseUrl, 10000, 10000); 47 | 48 | //Act 49 | var result = await SplitSdkApiClient.FetchSplitChanges(-1); 50 | 51 | //Assert 52 | Assert.IsTrue(result == string.Empty); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Resources/segment_payed.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "payed", 3 | "added": [ 4 | "abcdz", 5 | "bcadz", 6 | "xzydz" 7 | ], 8 | "removed": [], 9 | "since": -1, 10 | "till": 1470947453877 11 | } -------------------------------------------------------------------------------- /Splitio-net-core-tests/Resources/split.yaml: -------------------------------------------------------------------------------- 1 | # Always on 2 | - testing_split_on: 3 | treatment: "on" 4 | # This one will (or should) return control for non specified keys on whitelist 5 | - testing_split_only_wl: 6 | treatment: "whitelisted" 7 | keys: ["key_for_wl"] 8 | # Playing with whitelists 9 | - testing_split_with_wl: 10 | treatment: "not_in_whitelist" 11 | config: "{\"color\": \"green\"}" 12 | - testing_split_with_wl: 13 | treatment: "one_key_wl" 14 | keys: "key_for_wl" 15 | - testing_split_with_wl: 16 | treatment: "multi_key_wl" 17 | keys: ["key_for_wl_1", "key_for_wl_2"] 18 | config: "{\"color\": \"brown\"}" 19 | # All keys with config 20 | - testing_split_off_with_config: 21 | treatment: "off" 22 | config: "{\"color\": \"green\"}" -------------------------------------------------------------------------------- /Splitio-net-core-tests/Resources/split.yml: -------------------------------------------------------------------------------- 1 | # Always on 2 | - testing_split_on: 3 | treatment: "on" 4 | # This one will (or should) return control for non specified keys on whitelist 5 | - testing_split_only_wl: 6 | treatment: "whitelisted" 7 | keys: ["key_for_wl"] 8 | # Playing with whitelists 9 | - testing_split_with_wl: 10 | treatment: "not_in_whitelist" 11 | config: "{\"color\": \"green\"}" 12 | - testing_split_with_wl: 13 | treatment: "one_key_wl" 14 | keys: "key_for_wl" 15 | - testing_split_with_wl: 16 | treatment: "multi_key_wl" 17 | keys: ["key_for_wl_1", "key_for_wl_2"] 18 | config: "{\"color\": \"brown\"}" 19 | # All keys with config 20 | - testing_split_off_with_config: 21 | treatment: "off" 22 | config: "{\"color\": \"green\"}" -------------------------------------------------------------------------------- /Splitio-net-core-tests/Resources/splits_staging_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "splits": [ 3 | { 4 | "orgId": null, 5 | "environment": null, 6 | "trafficTypeId": null, 7 | "trafficTypeName": null, 8 | "name": "ta_bucket1_test", 9 | "algo": 2, 10 | "seed": -1222652054, 11 | "trafficAllocation": 1, 12 | "trafficAllocationSeed": -1667452163, 13 | "status": "ACTIVE", 14 | "killed": false, 15 | "defaultTreatment": "default_treatment", 16 | "conditions": [ 17 | { 18 | "conditionType": "ROLLOUT", 19 | "matcherGroup": { 20 | "combiner": "AND", 21 | "matchers": [ 22 | { 23 | "keySelector": { 24 | "trafficType": "user", 25 | "attribute": null 26 | }, 27 | "matcherType": "ALL_KEYS", 28 | "negate": false, 29 | "userDefinedSegmentMatcherData": null, 30 | "whitelistMatcherData": null, 31 | "unaryNumericMatcherData": null, 32 | "betweenMatcherData": null 33 | } 34 | ] 35 | }, 36 | "partitions": [ 37 | { 38 | "treatment": "rollout_treatment", 39 | "size": 100 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /Splitio-net-core-tests/Resources/test.splits: -------------------------------------------------------------------------------- 1 | # this is a comment 2 | 3 | reporting_v2 on # sdk.getTreatment(*, reporting_v2) will return 'on' 4 | 5 | double_writes_to_cassandra off 6 | 7 | other_test_feature on -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Cache/Lru/IDictionaryTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/mwdavis84/LruCacheNet 3 | Copyright (c) 2018 Mark Davis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using Splitio.Services.Cache.Lru; 26 | using System.Collections.Generic; 27 | 28 | namespace Splitio_Tests.Unit_Tests.Cache.Lru 29 | { 30 | [TestClass] 31 | public class IDictionaryTests 32 | { 33 | /// 34 | /// Tests that a handful of IDictionary interface methods work 35 | /// 36 | [TestMethod, TestCategory("IDictionary")] 37 | public void DictionaryTests() 38 | { 39 | IDictionary data = new LruCache(10); 40 | data[0] = 1; 41 | Assert.AreEqual(1, data.Count); 42 | Assert.AreEqual(1, data[0]); 43 | Assert.AreEqual(1, data.Keys.Count); 44 | Assert.AreEqual(1, data.Values.Count); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Cache/Lru/TestData.cs: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/mwdavis84/LruCacheNet 3 | Copyright (c) 2018 Mark Davis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | 24 | namespace Splitio_Tests.Unit_Tests.Cache.Lru 25 | { 26 | internal class TestData 27 | { 28 | public string TestValue1 { get; set; } 29 | 30 | public string TestValue2 { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Cache/RedisImpressionCacheTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Moq; 3 | using Splitio.Domain; 4 | using Splitio.Redis.Services.Cache.Classes; 5 | using Splitio.Redis.Services.Cache.Interfaces; 6 | using StackExchange.Redis; 7 | using System.Collections.Generic; 8 | 9 | namespace Splitio_Tests.Unit_Tests.Cache 10 | { 11 | [TestClass] 12 | public class RedisImpressionCacheTests 13 | { 14 | [TestMethod] 15 | public void AddImpressionSuccessfully() 16 | { 17 | //Arrange 18 | var key = "SPLITIO.impressions"; 19 | var redisAdapterMock = new Mock(); 20 | var cache = new RedisImpressionsCache(redisAdapterMock.Object, "10.0.0.1", "net-1.0.2", "machine_name_test"); 21 | var impressions = new List 22 | { 23 | new KeyImpression { feature = "test", changeNumber = 100, keyName = "date", label = "testdate", time = 10000000 } 24 | }; 25 | 26 | //Act 27 | cache.AddItems(impressions); 28 | 29 | //Assert 30 | redisAdapterMock.Verify(mock => mock.ListRightPush(key, It.IsAny())); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Client/LocalhostClientForTesting.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Client.Classes; 2 | using Splitio.Services.EngineEvaluator; 3 | using Splitio.Services.Logger; 4 | 5 | namespace Splitio_Tests.Unit_Tests.Client 6 | { 7 | public class LocalhostClientForTesting : LocalhostClient 8 | { 9 | public LocalhostClientForTesting(string filePath, 10 | ISplitLogger log = null, 11 | ISplitter splitter = null, 12 | bool isDestroyed = false) : base(filePath, log) 13 | { 14 | Destroyed = isDestroyed; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Splitio.Services.Client.Classes; 3 | 4 | namespace Splitio_Tests.Unit_Tests.Client 5 | { 6 | [TestClass] 7 | public class InMemoryReadinessGatesCacheUnitTests 8 | { 9 | [TestMethod] 10 | public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() 11 | { 12 | //Arrange 13 | var gates = new InMemoryReadinessGatesCache(); 14 | 15 | //Act 16 | var result = gates.IsSDKReady(0); 17 | 18 | //Assert 19 | Assert.IsFalse(result); 20 | } 21 | 22 | [TestMethod] 23 | public void IsSDKReadyShouldReturnFalseIfAnySegmentIsNotReady() 24 | { 25 | //Arrange 26 | var gates = new InMemoryReadinessGatesCache(); 27 | gates.RegisterSegment("any"); 28 | gates.SplitsAreReady(); 29 | 30 | //Act 31 | var result = gates.IsSDKReady(0); 32 | 33 | //Assert 34 | Assert.IsFalse(result); 35 | } 36 | 37 | [TestMethod] 38 | public void IsSDKReadyShouldReturnTrueIfSplitsAndSegmentsAreReady() 39 | { 40 | //Arrange 41 | var gates = new InMemoryReadinessGatesCache(); 42 | gates.RegisterSegment("any"); 43 | gates.RegisterSegment("other"); 44 | gates.SplitsAreReady(); 45 | gates.SegmentIsReady("other"); 46 | gates.SegmentIsReady("any"); 47 | 48 | //Act 49 | var result = gates.IsSDKReady(0); 50 | 51 | //Assert 52 | Assert.IsTrue(result); 53 | } 54 | 55 | [TestMethod] 56 | public void RegisterSegmentShouldReturnFalseIfSplitsAreReady() 57 | { 58 | //Arrange 59 | var gates = new InMemoryReadinessGatesCache(); 60 | gates.SplitsAreReady(); 61 | 62 | //Act 63 | var result = gates.RegisterSegment("any"); 64 | 65 | //Assert 66 | Assert.IsFalse(result); 67 | } 68 | 69 | [TestMethod] 70 | public void RegisterSegmentShouldReturnFalseIfSegmentNameEmpty() 71 | { 72 | //Arrange 73 | var gates = new InMemoryReadinessGatesCache(); 74 | 75 | //Act 76 | var result = gates.RegisterSegment(""); 77 | 78 | //Assert 79 | Assert.IsFalse(result); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Client/SplitClientForTesting.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Cache.Interfaces; 2 | using Splitio.Services.Client.Classes; 3 | using Splitio.Services.Evaluator; 4 | using Splitio.Services.Events.Interfaces; 5 | using Splitio.Services.Impressions.Interfaces; 6 | using Splitio.Services.InputValidation.Classes; 7 | using Splitio.Services.Logger; 8 | using Splitio.Services.Shared.Interfaces; 9 | 10 | namespace Splitio_Tests.Unit_Tests.Client 11 | { 12 | public class SplitClientForTesting : SplitClient 13 | { 14 | public SplitClientForTesting(ISplitLogger log, 15 | ISplitCache splitCache, 16 | IEventsLog eventsLog, 17 | IImpressionsLog impressionsLog, 18 | IBlockUntilReadyService blockUntilReadyService, 19 | IEvaluator evaluator, 20 | IImpressionsManager impressionsManager) 21 | : base(log) 22 | { 23 | _splitCache = splitCache; 24 | _eventsLog = eventsLog; 25 | _impressionsLog = impressionsLog; 26 | _blockUntilReadyService = blockUntilReadyService; 27 | _trafficTypeValidator = new TrafficTypeValidator(_splitCache, log); 28 | _evaluator = evaluator; 29 | _impressionsManager = impressionsManager; 30 | 31 | ApiKey = "SplitClientForTesting"; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Events/RedisEventsLogUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Moq; 3 | using Splitio.Domain; 4 | using Splitio.Redis.Services.Events.Classes; 5 | using Splitio.Services.Shared.Interfaces; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace Splitio_Tests.Unit_Tests.Events 10 | { 11 | [TestClass] 12 | public class RedisEventsLogUnitTests 13 | { 14 | private readonly Mock> _eventsCacheMock; 15 | private readonly RedisEvenstLog _redisEventsLog; 16 | 17 | public RedisEventsLogUnitTests() 18 | { 19 | _eventsCacheMock = new Mock>(); 20 | 21 | _redisEventsLog = new RedisEvenstLog(_eventsCacheMock.Object); 22 | } 23 | 24 | [TestMethod] 25 | public void LogSuccessfully() 26 | { 27 | //Arrange 28 | var eventToLog = new Event { key = "Key1", eventTypeId = "testEventType", trafficTypeName = "testTrafficType", timestamp = 7000, value = 12.34 }; 29 | 30 | var wrappedEvent = new WrappedEvent 31 | { 32 | Event = eventToLog, 33 | Size = 1024 34 | }; 35 | 36 | //Act 37 | _redisEventsLog.Log(wrappedEvent); 38 | 39 | //Assert 40 | _eventsCacheMock.Verify(mock => mock.AddItems(It.IsAny>()), Times.Once()); 41 | } 42 | 43 | [TestMethod] 44 | [ExpectedException(typeof(NotImplementedException))] 45 | public void Start_ReturnsException() 46 | { 47 | //Act 48 | _redisEventsLog.Start(); 49 | } 50 | 51 | [TestMethod] 52 | [ExpectedException(typeof(NotImplementedException))] 53 | public void Stop_ReturnsException() 54 | { 55 | //Act 56 | _redisEventsLog.Stop(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Splitio.Services.Impressions.Classes; 3 | using Splitio_Tests.Resources; 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Splitio_Tests.Unit_Tests.Impressions 8 | { 9 | [TestClass] 10 | public class ImpressionsCounterTests 11 | { 12 | [TestMethod] 13 | public void IncBasicUsage() 14 | { 15 | // Arrange. 16 | var impressionsCounter = new ImpressionsCounter(); 17 | 18 | impressionsCounter.Inc("feature1", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 15, 11, DateTimeKind.Utc))); 19 | impressionsCounter.Inc("feature1", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 20, 11, DateTimeKind.Utc))); 20 | impressionsCounter.Inc("feature1", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 50, 11, DateTimeKind.Utc))); 21 | impressionsCounter.Inc("feature2", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 50, 11, DateTimeKind.Utc))); 22 | impressionsCounter.Inc("feature2", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 55, 11, DateTimeKind.Utc))); 23 | impressionsCounter.Inc("feature1", SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 50, 11, DateTimeKind.Utc))); 24 | 25 | // Act. 26 | var result = impressionsCounter.PopAll(); 27 | 28 | // Assert. 29 | Assert.AreEqual(3, result.FirstOrDefault(x => x.Key.SplitName.Equals("feature1") && x.Key.TimeFrame.Equals(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 0, 0, DateTimeKind.Utc)))).Value); 30 | Assert.AreEqual(2, result.FirstOrDefault(x => x.Key.SplitName.Equals("feature2") && x.Key.TimeFrame.Equals(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 09, 0, 0, DateTimeKind.Utc)))).Value); 31 | Assert.AreEqual(1, result.FirstOrDefault(x => x.Key.SplitName.Equals("feature1") && x.Key.TimeFrame.Equals(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 0, 0, DateTimeKind.Utc)))).Value); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Impressions/ImpressionsHelperTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Splitio.Services.Impressions.Classes; 3 | using Splitio_Tests.Resources; 4 | using System; 5 | 6 | namespace Splitio_Tests.Unit_Tests.Impressions 7 | { 8 | [TestClass] 9 | public class ImpressionsHelperTest 10 | { 11 | [TestMethod] 12 | public void TruncateTimeFrame() 13 | { 14 | var expected = SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 0, 0, DateTimeKind.Utc)); 15 | Assert.AreEqual(expected, ImpressionsHelper.TruncateTimeFrame(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 53, 12, DateTimeKind.Utc)))); 16 | Assert.AreEqual(expected, ImpressionsHelper.TruncateTimeFrame(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 00, 00, DateTimeKind.Utc)))); 17 | Assert.AreEqual(expected, ImpressionsHelper.TruncateTimeFrame(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 53, 00, DateTimeKind.Utc)))); 18 | Assert.AreEqual(expected, ImpressionsHelper.TruncateTimeFrame(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 10, 00, 12, DateTimeKind.Utc)))); 19 | 20 | expected = SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 00, 00, 00, DateTimeKind.Utc)); 21 | Assert.AreEqual(expected, ImpressionsHelper.TruncateTimeFrame(SplitsHelper.MakeTimestamp(new DateTime(2020, 09, 02, 00, 00, 00, DateTimeKind.Utc)))); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/InputValidation/ApiKeyValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Moq; 3 | using Splitio.Services.InputValidation.Classes; 4 | using Splitio.Services.Logger; 5 | 6 | namespace Splitio_Tests.Unit_Tests.InputValidation 7 | { 8 | [TestClass] 9 | public class ApiKeyValidatorTests 10 | { 11 | private Mock _log; 12 | private ApiKeyValidator apiKeyValidator; 13 | 14 | [TestInitialize] 15 | public void Initialize() 16 | { 17 | _log = new Mock(); 18 | 19 | apiKeyValidator = new ApiKeyValidator(_log.Object); 20 | } 21 | 22 | [TestMethod] 23 | public void Validate_WhenApiKeyIsEmpty_LogOneError() 24 | { 25 | //Arrange 26 | var apiKey = string.Empty; 27 | 28 | //Act 29 | apiKeyValidator.Validate(apiKey); 30 | 31 | //Assert 32 | _log.Verify(mock => mock.Error($"factory instantiation: you passed and empty api_key, api_key must be a non-empty string."), Times.Once()); 33 | } 34 | 35 | [TestMethod] 36 | public void Validate_WhenApiKeyIsNull_LogOneError() 37 | { 38 | //Arrange 39 | string apiKey = null; 40 | 41 | //Act 42 | apiKeyValidator.Validate(apiKey); 43 | 44 | //Assert 45 | _log.Verify(mock => mock.Error($"factory instantiation: you passed a null api_key, api_key must be a non-empty string."), Times.Once()); 46 | } 47 | 48 | [TestMethod] 49 | public void Validate_WhenApiKeyHasValue_NoLog() 50 | { 51 | //Arrange 52 | string apiKey = "api_key"; 53 | 54 | //Act 55 | apiKeyValidator.Validate(apiKey); 56 | 57 | //Assert 58 | _log.Verify(mock => mock.Error(It.IsAny()), Times.Never()); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/Matchers/AllKeysMatcherTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Splitio.Domain; 3 | using Splitio.Services.Parsing; 4 | 5 | namespace Splitio_Tests.Unit_Tests 6 | { 7 | [TestClass] 8 | public class AllKeysMatcherTests 9 | { 10 | [TestMethod] 11 | public void MatchShouldReturnTrueForAnyKey() 12 | { 13 | //Arrange 14 | var matcher = new AllKeysMatcher(); 15 | 16 | //Act 17 | var result = matcher.Match(new Key("test", "test")); 18 | 19 | //Assert 20 | Assert.IsTrue(result); 21 | } 22 | 23 | [TestMethod] 24 | public void MatchShouldReturnFalseIfNull() 25 | { 26 | //Arrange 27 | var matcher = new AllKeysMatcher(); 28 | 29 | //Act 30 | var result2 = matcher.Match(new Key((string)null, null)); 31 | 32 | //Assert 33 | Assert.IsFalse(result2); 34 | } 35 | 36 | [TestMethod] 37 | public void MatchShouldReturnTrueForAnyStringKey() 38 | { 39 | //Arrange 40 | var matcher = new AllKeysMatcher(); 41 | 42 | //Act 43 | var result = matcher.Match("test"); 44 | 45 | //Assert 46 | Assert.IsTrue(result); 47 | } 48 | 49 | [TestMethod] 50 | public void MatchShouldReturnFalseIfNullString() 51 | { 52 | //Arrange 53 | var matcher = new AllKeysMatcher(); 54 | 55 | //Act 56 | var result2 = matcher.Match((string)null); 57 | 58 | //Assert 59 | Assert.IsFalse(result2); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Splitio-net-core-tests/Unit Tests/SegmentFetcher/ApiSegmentChangeFetcherUnitTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Moq; 3 | using Splitio.Services.SegmentFetcher.Classes; 4 | using Splitio.Services.SplitFetcher.Interfaces; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace Splitio_Tests.Unit_Tests.SegmentFetcher 9 | { 10 | [TestClass] 11 | public class ApiSegmentChangeFetcherUnitTests 12 | { 13 | [TestMethod] 14 | public async Task FetchSegmentChangesSuccessfull() 15 | { 16 | //Arrange 17 | var apiClient = new Mock(); 18 | apiClient 19 | .Setup(x=>x.FetchSegmentChanges(It.IsAny(), It.IsAny())) 20 | .Returns(Task.FromResult(@"{ 21 | 'name': 'payed', 22 | 'added': [ 23 | 'abcdz', 24 | 'bcadz', 25 | 'xzydz' 26 | ], 27 | 'removed': [], 28 | 'since': -1, 29 | 'till': 1470947453877 30 | }")); 31 | var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); 32 | 33 | //Act 34 | var result = await apiFetcher.Fetch("payed", -1); 35 | 36 | //Assert 37 | Assert.IsNotNull(result); 38 | Assert.AreEqual("payed", result.name); 39 | Assert.AreEqual(-1, result.since); 40 | Assert.AreEqual(1470947453877, result.till); 41 | Assert.AreEqual(3, result.added.Count); 42 | Assert.AreEqual(0, result.removed.Count); 43 | } 44 | 45 | [TestMethod] 46 | public async Task FetchSegmentChangesWithExcepionSouldReturnNull() 47 | { 48 | var apiClient = new Mock(); 49 | apiClient 50 | .Setup(x => x.FetchSegmentChanges(It.IsAny(), It.IsAny())) 51 | .Throws(new Exception()); 52 | var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); 53 | 54 | //Act 55 | var result = await apiFetcher.Fetch("payed", -1); 56 | 57 | //Assert 58 | Assert.IsNull(result); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/EventBackend.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio_net_core.Integration_tests.Resources 4 | { 5 | public class EventBackend 6 | { 7 | public string Key { get; set; } 8 | public string EventTypeId { get; set; } 9 | public string TrafficTypeName { get; set; } 10 | public double? Value { get; set; } 11 | public long Timestamp { get; set; } 12 | public Dictionary Properties { get; set; } 13 | } 14 | 15 | public class EventRedis 16 | { 17 | public MachineRedis M { get; set; } 18 | public EventBackend E { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/IntegrationTestsImpressionListener.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Impressions.Interfaces; 3 | using Splitio.Services.Shared.Classes; 4 | 5 | namespace Splitio_net_core.Integration_tests.Resources 6 | { 7 | public class IntegrationTestsImpressionListener : IImpressionListener 8 | { 9 | BlockingQueue queue; 10 | 11 | public IntegrationTestsImpressionListener(int size) 12 | { 13 | queue = new BlockingQueue(size); 14 | } 15 | 16 | public void Log(KeyImpression impression) 17 | { 18 | if (queue.HasReachedMaxSize()) 19 | { 20 | queue.Dequeue(); 21 | } 22 | 23 | queue.Enqueue(impression); 24 | } 25 | 26 | public BlockingQueue GetQueue() 27 | { 28 | return queue; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/KeyImpressionBackend.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio_net_core.Integration_tests.Resources 4 | { 5 | public class KeyImpressionBackend 6 | { 7 | public string F { get; set; } 8 | public List I { get; set; } 9 | } 10 | 11 | public class ImpressionData 12 | { 13 | public string K { get; set; } 14 | public string B { get; set; } 15 | public string T { get; set; } 16 | public string R { get; set; } 17 | public long? C { get; set; } 18 | public long? M { get; set; } 19 | } 20 | 21 | public class KeyImpressionRedis 22 | { 23 | public MachineRedis M { get; set; } 24 | public InfoRedis I { get; set; } 25 | } 26 | 27 | public class MachineRedis 28 | { 29 | public string S { get; set; } 30 | public string I { get; set; } 31 | public string N { get; set; } 32 | } 33 | 34 | public class InfoRedis 35 | { 36 | public string K { get; set; } 37 | public string B { get; set; } 38 | public string F { get; set; } 39 | public string T { get; set; } 40 | public string R { get; set; } 41 | public long? C { get; set; } 42 | public long? M { get; set; } 43 | } 44 | 45 | public class ImpressionCount 46 | { 47 | public List Pf { get; set; } 48 | } 49 | 50 | public class ImpressionCountData 51 | { 52 | public string F { get; set; } 53 | public long M { get; set; } 54 | public int Rc { get; set; } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/StatusCodeEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio_net_core.Integration_tests.Resources 2 | { 3 | public enum StatusCodeEnum 4 | { 5 | BadRequest = 400, 6 | InternalServerError = 500 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_changes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitio/.net-core-client/619ef84a06f44914d6d03a673ffdeab0d36039b8/Splitio-net-core.Integration-tests/Resources/split_changes.json -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_changes_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "splits": [], 3 | "since": 1506703262916, 4 | "till": 1506703262916 5 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment1", 3 | "added": [ 4 | "Test" 5 | ], 6 | "removed": [], 7 | "since": -1, 8 | "till": 1470947453877 9 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment2", 3 | "added": [ 4 | "testo2222", 5 | "a_new_split_2" 6 | ], 7 | "removed": [], 8 | "since": -1, 9 | "till": 1470947453878 10 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment3", 3 | "added": [ 4 | "testo2222", 5 | "test_string_without_attr", 6 | "Test_Save_1" 7 | ], 8 | "removed": [], 9 | "since": -1, 10 | "till": -1 11 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment4.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment4", 3 | "added": [ 4 | "test_in_segment" 5 | ], 6 | "removed": [], 7 | "since": -1, 8 | "till": 1470947453878 9 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment4_empty.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment4", 3 | "added": [ 4 | "test_in_segment" 5 | ], 6 | "removed": [], 7 | "since": 1470947453878, 8 | "till": 1470947453878 9 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment4_updated.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment4", 3 | "added": [], 4 | "removed": [ "test_in_segment" ], 5 | "since": 1470947453878, 6 | "till": 1470947453879 7 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/split_segment4_updated_empty.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "segment4", 3 | "added": [], 4 | "removed": [ "test_in_segment" ], 5 | "since": 1470947453879, 6 | "till": 1470947453879 7 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/splits_push2.json: -------------------------------------------------------------------------------- 1 | { 2 | "splits": [], 3 | "since": 1585948850109, 4 | "till": 1585948850109 5 | } -------------------------------------------------------------------------------- /Splitio-net-core.Integration-tests/Resources/splits_push4.json: -------------------------------------------------------------------------------- 1 | { 2 | "splits": [], 3 | "since": 1585948850111, 4 | "till": 1585948850111 5 | } -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Cache/Classes/RedisCacheBase.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Redis.Services.Cache.Interfaces; 2 | 3 | namespace Splitio.Redis.Services.Cache.Classes 4 | { 5 | public abstract class RedisCacheBase 6 | { 7 | private const string RedisKeyPrefixFormat = "SPLITIO/{sdk-language-version}/{instance-id}/"; 8 | 9 | protected IRedisAdapter _redisAdapter; 10 | 11 | protected string RedisKeyPrefix; 12 | protected string UserPrefix; 13 | protected string SdkVersion; 14 | protected string MachineIp; 15 | protected string MachineName; 16 | 17 | public RedisCacheBase(IRedisAdapter redisAdapter, 18 | string userPrefix = null) 19 | { 20 | _redisAdapter = redisAdapter; 21 | 22 | UserPrefix = userPrefix; 23 | RedisKeyPrefix = "SPLITIO."; 24 | 25 | if (!string.IsNullOrEmpty(userPrefix)) 26 | { 27 | RedisKeyPrefix = userPrefix + "." + RedisKeyPrefix; 28 | } 29 | } 30 | 31 | public RedisCacheBase(IRedisAdapter redisAdapter, 32 | string machineIP, 33 | string sdkVersion, 34 | string machineName, 35 | string userPrefix = null) 36 | { 37 | _redisAdapter = redisAdapter; 38 | 39 | UserPrefix = userPrefix; 40 | MachineIp = machineIP; 41 | SdkVersion = sdkVersion; 42 | MachineName = machineName; 43 | 44 | RedisKeyPrefix = RedisKeyPrefixFormat 45 | .Replace("{sdk-language-version}", sdkVersion) 46 | .Replace("{instance-id}", machineIP); 47 | 48 | if (!string.IsNullOrEmpty(userPrefix)) 49 | { 50 | RedisKeyPrefix = userPrefix + "." + RedisKeyPrefix; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Cache/Classes/RedisEventsCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | using Splitio.Domain; 4 | using Splitio.Redis.Services.Cache.Interfaces; 5 | using Splitio.Services.Shared.Interfaces; 6 | 7 | namespace Splitio.Redis.Services.Cache.Classes 8 | { 9 | public class RedisEventsCache : RedisCacheBase, ISimpleCache 10 | { 11 | private readonly string _machineName; 12 | private readonly string _machineIP; 13 | private readonly string _sdkVersion; 14 | 15 | public RedisEventsCache(IRedisAdapter redisAdapter, 16 | string machineName, 17 | string machineIP, 18 | string sdkVersion, 19 | string userPrefix = null) : base(redisAdapter, userPrefix) 20 | { 21 | _machineName = machineName; 22 | _machineIP = machineIP; 23 | _sdkVersion = sdkVersion; 24 | } 25 | 26 | public void AddItems(IList items) 27 | { 28 | foreach (var item in items) 29 | { 30 | var eventJson = JsonConvert.SerializeObject(new 31 | { 32 | m = new { s = _sdkVersion, i = _machineIP, n = _machineName }, 33 | e = item.Event 34 | }); 35 | 36 | _redisAdapter.ListRightPush($"{RedisKeyPrefix}events", eventJson); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Cache/Classes/RedisImpressionsCache.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.Domain; 3 | using Splitio.Redis.Services.Cache.Interfaces; 4 | using Splitio.Services.Shared.Interfaces; 5 | using StackExchange.Redis; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Splitio.Redis.Services.Cache.Classes 11 | { 12 | public class RedisImpressionsCache : RedisCacheBase, ISimpleCache 13 | { 14 | public RedisImpressionsCache(IRedisAdapter redisAdapter, 15 | string machineIP, 16 | string sdkVersion, 17 | string machineName, 18 | string userPrefix = null) : base(redisAdapter, machineIP, sdkVersion, machineName, userPrefix) 19 | { } 20 | 21 | public void AddItems(IList items) 22 | { 23 | var key = string.Format("{0}SPLITIO.impressions", string.IsNullOrEmpty(UserPrefix) ? string.Empty : $"{UserPrefix}."); 24 | 25 | var impressions = items.Select(item => JsonConvert.SerializeObject(new 26 | { 27 | m = new { s = SdkVersion, i = MachineIp, n = MachineName }, 28 | i = new { k = item.keyName, b = item.bucketingKey, f = item.feature, t = item.treatment, r = item.label, c = item.changeNumber, m = item.time } 29 | })); 30 | 31 | var lengthRedis = _redisAdapter.ListRightPush(key, impressions.Select(i => (RedisValue)i).ToArray()); 32 | 33 | if (lengthRedis == items.Count) 34 | { 35 | _redisAdapter.KeyExpire(key, new TimeSpan(0, 0, 3600)); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Cache/Interfaces/IRedisAdapter.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | using System; 3 | 4 | namespace Splitio.Redis.Services.Cache.Interfaces 5 | { 6 | public interface IRedisAdapter 7 | { 8 | bool Set(string key, string value); 9 | 10 | string Get(string key); 11 | 12 | RedisValue[] MGet(RedisKey[] keys); 13 | 14 | RedisKey[] Keys(string pattern); 15 | 16 | bool Del(string key); 17 | 18 | long Del(RedisKey[] keys); 19 | 20 | bool SAdd(string key, RedisValue value); 21 | 22 | long SAdd(string key, RedisValue[] values); 23 | 24 | long SRem(string key, RedisValue[] values); 25 | 26 | long ListRightPush(string key, RedisValue value); 27 | 28 | long ListRightPush(string key, RedisValue[] values); 29 | 30 | bool SIsMember(string key, string value); 31 | 32 | RedisValue[] SMembers(string key); 33 | 34 | long IcrBy(string key, long delta); 35 | 36 | void Flush(); 37 | 38 | bool IsConnected(); 39 | 40 | bool KeyExpire(string key, TimeSpan expiry); 41 | 42 | RedisValue[] ListRange(RedisKey key, long start = 0, long stop = -1); 43 | 44 | void Connect(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Domain/RedisConfig.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Redis.Services.Domain 4 | { 5 | public class RedisConfig : BaseConfig 6 | { 7 | public string RedisHost { get; set; } 8 | public string RedisPort { get; set; } 9 | public string RedisPassword { get; set; } 10 | public string RedisUserPrefix { get; set; } 11 | public int RedisDatabase { get; set; } 12 | public int RedisConnectTimeout { get; set; } 13 | public int RedisConnectRetry { get; set; } 14 | public int RedisSyncTimeout { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Events/Classes/RedisEventsLog.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Events.Interfaces; 3 | using Splitio.Services.Shared.Interfaces; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Redis.Services.Events.Classes 7 | { 8 | public class RedisEvenstLog : IEventsLog 9 | { 10 | private readonly ISimpleCache _eventsCache; 11 | 12 | public RedisEvenstLog(ISimpleCache eventsCache) 13 | { 14 | _eventsCache = eventsCache; 15 | } 16 | 17 | public void Log(WrappedEvent wrappedEvent) 18 | { 19 | _eventsCache.AddItems(new List { wrappedEvent }); 20 | } 21 | 22 | public void Start() 23 | { 24 | throw new System.NotImplementedException(); 25 | } 26 | 27 | public void Stop() 28 | { 29 | throw new System.NotImplementedException(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Impressions/Classes/RedisImpressionLog.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Splitio.Domain; 3 | using Splitio.Services.Impressions.Interfaces; 4 | using Splitio.Services.Shared.Interfaces; 5 | 6 | namespace Splitio.Redis.Services.Impressions.Classes 7 | { 8 | public class RedisImpressionLog : IImpressionsLog 9 | { 10 | private readonly ISimpleCache _impressionsCache; 11 | 12 | public RedisImpressionLog(ISimpleCache impressionsCache) 13 | { 14 | _impressionsCache = impressionsCache; 15 | } 16 | 17 | public void Log(IList impressions) 18 | { 19 | _impressionsCache.AddItems(impressions); 20 | } 21 | 22 | public void Start() 23 | { 24 | throw new System.NotImplementedException(); 25 | } 26 | 27 | public void Stop() 28 | { 29 | throw new System.NotImplementedException(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Metrics/Classes/RedisMetricsLog.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Cache.Interfaces; 2 | using Splitio.Services.Metrics.Interfaces; 3 | 4 | namespace Splitio.Redis.Services.Metrics.Classes 5 | { 6 | public class RedisMetricsLog : IMetricsLog 7 | { 8 | IMetricsCache metricsCache; 9 | 10 | public RedisMetricsLog(IMetricsCache metricsCache) 11 | { 12 | this.metricsCache = metricsCache; 13 | } 14 | 15 | public void Count(string counterName, long delta) 16 | { 17 | if (string.IsNullOrEmpty(counterName) || delta <= 0) 18 | { 19 | return; 20 | } 21 | 22 | metricsCache.IncrementCount(counterName, delta); 23 | } 24 | 25 | public void Time(string operation, long miliseconds) 26 | { 27 | if (string.IsNullOrEmpty(operation) || miliseconds < 0) 28 | { 29 | return; 30 | } 31 | 32 | metricsCache.SetLatency(operation, miliseconds); 33 | } 34 | 35 | public void Gauge(string gauge, long value) 36 | { 37 | if (string.IsNullOrEmpty(gauge) || value < 0) 38 | { 39 | return; 40 | } 41 | 42 | metricsCache.SetGauge(gauge, value); 43 | } 44 | 45 | public void Clear() 46 | { 47 | return; 48 | } 49 | 50 | public void Start() 51 | { 52 | return; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Parsing/Classes/RedisSplitParser.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Interfaces; 3 | using Splitio.Services.Parsing; 4 | 5 | namespace Splitio.Redis.Services.Parsing.Classes 6 | { 7 | public class RedisSplitParser : SplitParser 8 | { 9 | public RedisSplitParser(ISegmentCache segmentsCache) 10 | { 11 | _segmentsCache = segmentsCache; 12 | } 13 | 14 | protected override IMatcher GetInSegmentMatcher(MatcherDefinition matcherDefinition, ParsedSplit parsedSplit) 15 | { 16 | var matcherData = matcherDefinition.userDefinedSegmentMatcherData; 17 | 18 | return new UserDefinedSegmentMatcher(matcherData.segmentName, _segmentsCache); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/Services/Shared/RedisBlockUntilReadyService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Redis.Services.Cache.Interfaces; 2 | using Splitio.Services.Shared.Interfaces; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Threading; 6 | 7 | namespace Splitio.Redis.Services.Shared 8 | { 9 | public class RedisBlockUntilReadyService : IBlockUntilReadyService 10 | { 11 | private readonly IRedisAdapter _redisAdapter; 12 | 13 | public RedisBlockUntilReadyService(IRedisAdapter redisAdapter) 14 | { 15 | _redisAdapter = redisAdapter; 16 | } 17 | 18 | public void BlockUntilReady(int blockMilisecondsUntilReady) 19 | { 20 | if (!IsSdkReady()) 21 | { 22 | var ready = false; 23 | var clock = new Stopwatch(); 24 | clock.Start(); 25 | 26 | while (clock.ElapsedMilliseconds <= blockMilisecondsUntilReady) 27 | { 28 | if (IsSdkReady()) 29 | { 30 | ready = true; 31 | break; 32 | } 33 | } 34 | 35 | if (!ready) throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady}. Could not connect to Redis"); 36 | } 37 | } 38 | 39 | public bool IsSdkReady() 40 | { 41 | return _redisAdapter.IsConnected(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Splitio-net-core.Redis/SplitioRedis.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitio/.net-core-client/619ef84a06f44914d6d03a673ffdeab0d36039b8/Splitio-net-core.Redis/SplitioRedis.snk -------------------------------------------------------------------------------- /Splitio.TestSupport/SplitClientForTest.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Logger; 3 | using System.Collections.Generic; 4 | 5 | namespace Splitio.Services.Client.Classes 6 | { 7 | public class SplitClientForTest : SplitClient 8 | { 9 | private Dictionary _tests; 10 | 11 | public SplitClientForTest(ISplitLogger log) : base(log) 12 | { 13 | _tests = new Dictionary(); 14 | } 15 | 16 | public override void Destroy() 17 | { 18 | _tests = new Dictionary(); 19 | } 20 | 21 | public void ClearTreatments() 22 | { 23 | _tests = new Dictionary(); 24 | } 25 | 26 | public void RegisterTreatments(Dictionary treatments) 27 | { 28 | foreach (var treatment in treatments) 29 | { 30 | if (!_tests.ContainsKey(treatment.Key)) 31 | { 32 | _tests.Add(treatment.Key, treatment.Value); 33 | } 34 | } 35 | } 36 | 37 | public void RegisterTreatment(string feature, string treatment) 38 | { 39 | _tests.Add(feature, treatment); 40 | } 41 | 42 | public string GetTreatment(string key, string feature) 43 | { 44 | return _tests.ContainsKey(feature) ? _tests[feature] : "control"; 45 | } 46 | 47 | public override string GetTreatment(string key, string feature, Dictionary attributes = null) 48 | { 49 | return GetTreatment(key, feature); 50 | } 51 | 52 | public override string GetTreatment(Key key, string feature, Dictionary attributes = null) 53 | { 54 | return _tests.ContainsKey(feature) ? _tests[feature] : "control"; 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Splitio.TestSupport/SplitScenario.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using Xunit; 6 | 7 | namespace Splitio.TestSupport 8 | { 9 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 10 | public class SplitScenario : ClassDataAttribute 11 | { 12 | public SplitTest[] features { get; private set; } 13 | 14 | [JsonConstructor] 15 | public SplitScenario(SplitTest[] features) : base(typeof(object)) 16 | { 17 | this.features = features; 18 | } 19 | 20 | public SplitScenario(string features) : base(typeof(object)) 21 | { 22 | this.features = JsonConvert.DeserializeObject(features); 23 | } 24 | 25 | public override IEnumerable GetData(MethodInfo methodUnderTest) 26 | { 27 | var data = new List(); 28 | foreach (var splitTest in this.features) 29 | { 30 | foreach (var treatment in splitTest.treatments) 31 | { 32 | data.Add(new string[] { splitTest.feature, treatment }); 33 | } 34 | } 35 | return data; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Splitio.TestSupport/SplitSuite.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using Xunit; 6 | 7 | namespace Splitio.TestSupport 8 | { 9 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 10 | public class SplitSuite : ClassDataAttribute 11 | { 12 | public SplitScenario[] splitScenarios { get; private set; } 13 | 14 | public SplitSuite(string scenarios) : base(typeof(object)) 15 | { 16 | this.splitScenarios = JsonConvert.DeserializeObject(scenarios); 17 | } 18 | 19 | public override IEnumerable GetData(MethodInfo methodUnderTest) 20 | { 21 | var data = new List(); 22 | foreach (var splitScenario in this.splitScenarios) 23 | { 24 | foreach (var splitTest in splitScenario.features) 25 | { 26 | foreach (var treatment in splitTest.treatments) 27 | { 28 | data.Add(new string[] { splitTest.feature, treatment }); 29 | } 30 | } 31 | } 32 | return data; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Splitio.TestSupport/SplitTest.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using Xunit; 6 | 7 | namespace Splitio.TestSupport 8 | { 9 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 10 | public class SplitTest : ClassDataAttribute 11 | { 12 | public string feature { get; private set; } 13 | public string[] treatments { get; private set; } 14 | 15 | [JsonConstructor] 16 | public SplitTest(string feature, string[] treatments) 17 | : base(typeof(object)) 18 | { 19 | this.feature = feature; 20 | this.treatments = treatments; 21 | } 22 | 23 | public SplitTest(string test) : base(typeof(object)) 24 | { 25 | var splitTest = JsonConvert.DeserializeObject(test); 26 | this.feature = splitTest.feature; 27 | this.treatments = splitTest.treatments; 28 | } 29 | 30 | public override IEnumerable GetData(MethodInfo methodUnderTest) 31 | { 32 | var data = new List(); 33 | foreach (var treatment in treatments) 34 | { 35 | data.Add(new string[] { feature, treatment }); 36 | } 37 | return data; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Splitio.TestSupport/Splitio-net-core.TestSupport.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2;netcoreapp2.1;netcoreapp2.0;netcoreapp1.1;netcoreapp1.0;net472;net471;net47;net462;net461;net46;net452;net451;net45 5 | 3.3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | nuget: 2 | account_feed: true 3 | 4 | version: 6.2.4-rc{build} 5 | 6 | dotnet_csproj: 7 | patch: true 8 | file: '**\*.csproj' 9 | package_version: '{version}' 10 | 11 | configuration: Release 12 | 13 | before_build: 14 | - choco install "sonarscanner-msbuild-net46" -y 15 | - nuget install redis-64 -excludeversion -source http://www.nuget.org/api/v2/ 16 | - Redis-64\tools\redis-server.exe --service-install 17 | - dotnet restore -s https://www.nuget.org/api/v2/ 18 | - cmd: set BUILD_VERSION=%APPVEYOR_BUILD_NUMBER% 19 | 20 | build_script: 21 | - sonar-scanner.bat 22 | - dotnet build --configuration Release 23 | - SonarScanner.MSBuild.exe end /d:sonar.login=%SONAR_LOGIN% 24 | 25 | after_build: 26 | - Redis-64\tools\redis-server.exe --service-start 27 | - dotnet test .\Splitio-net-core-tests\Splitio-net-core-tests.csproj --configuration Release --framework netcoreapp2.2 28 | - Redis-64\tools\redis-server.exe --service-stop 29 | - Redis-64\tools\redis-server.exe --service-start 30 | - dotnet test .\Splitio-net-core-tests\Splitio-net-core-tests.csproj --configuration Release --framework netcoreapp1.0 31 | - Redis-64\tools\redis-server.exe --service-stop 32 | - Redis-64\tools\redis-server.exe --service-start 33 | - dotnet test .\Splitio-net-core-tests\Splitio-net-core-tests.csproj --configuration Release --framework net472 34 | - Redis-64\tools\redis-server.exe --service-stop 35 | - Redis-64\tools\redis-server.exe --service-start 36 | - dotnet test .\Splitio-net-core-tests\Splitio-net-core-tests.csproj --configuration Release --framework net462 37 | - Redis-64\tools\redis-server.exe --service-stop 38 | - Redis-64\tools\redis-server.exe --service-start 39 | - dotnet test .\Splitio-net-core-tests\Splitio-net-core-tests.csproj --configuration Release --framework net45 40 | - Redis-64\tools\redis-server.exe --service-stop 41 | - Redis-64\tools\redis-server.exe --service-start 42 | - dotnet test .\Splitio-net-core.Integration-tests\Splitio-net-core.Integration-tests.csproj --configuration Release --framework netcoreapp2.2 43 | - dotnet test .\Splitio.TestSupport\Splitio-net-core.TestSupport.csproj --configuration Release 44 | - dotnet pack .\src\Splitio-net-core --configuration Release 45 | - dotnet pack .\Splitio-net-core.Redis --configuration Release 46 | - dotnet pack .\Splitio.TestSupport --configuration Release 47 | 48 | test: off 49 | 50 | artifacts: 51 | - path: '**\Splitio*.nupkg' 52 | name: splitio-nuget 53 | 54 | deploy: 55 | - provider: Environment 56 | name: NugetNetCorePublish 57 | on: 58 | branch: master 59 | -------------------------------------------------------------------------------- /lib/MurmurHash-net-core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitio/.net-core-client/619ef84a06f44914d6d03a673ffdeab0d36039b8/lib/MurmurHash-net-core.dll -------------------------------------------------------------------------------- /sonar-scanner.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal EnableDelayedExpansion 3 | GOTO :main 4 | 5 | :sonar_scanner 6 | SonarScanner.MSBuild.exe begin ^ 7 | /n:".net-core-client" ^ 8 | /k:"net-core-client" ^ 9 | /v:"%APPVEYOR_BUILD_VERSION%" ^ 10 | /d:sonar.host.url="https://sonarqube.split-internal.com" ^ 11 | /d:sonar.login="%SONAR_LOGIN%" ^ 12 | /d:sonar.ws.timeout="300" ^ 13 | /d:sonar.links.ci="https://travis-ci.com/splitio/.net-core-client" ^ 14 | /d:sonar.links.scm="https://github.com/splitio/.net-core-client" ^ 15 | %* 16 | EXIT /B 0 17 | 18 | :main 19 | IF NOT "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" ( 20 | echo Pull Request number %APPVEYOR_PULL_REQUEST_NUMBER% 21 | CALL :sonar_scanner ^ 22 | "/d:sonar.pullrequest.provider="GitHub"" ^ 23 | "/d:sonar.pullrequest.github.repository="splitio/.net-core-client"" ^ 24 | "/d:sonar.pullrequest.key="%APPVEYOR_PULL_REQUEST_NUMBER%"" ^ 25 | "/d:sonar.pullrequest.branch="%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%"" ^ 26 | "/d:sonar.pullrequest.base="%APPVEYOR_REPO_BRANCH%"" 27 | ) ELSE ( 28 | IF "%APPVEYOR_REPO_BRANCH%"=="master" ( 29 | echo "Master branch." 30 | CALL :sonar_scanner ^ 31 | "/d:sonar.branch.name="%APPVEYOR_REPO_BRANCH%"" 32 | ) ELSE ( 33 | IF "%APPVEYOR_REPO_BRANCH%"=="development" ( 34 | echo "Development branch." 35 | SET "TARGET_BRANCH=master" 36 | ) ELSE ( 37 | echo "Feature branch." 38 | SET "TARGET_BRANCH=development" 39 | ) 40 | echo Branch Name is %APPVEYOR_REPO_BRANCH% 41 | echo Target Branch is !TARGET_BRANCH! 42 | CALL :sonar_scanner ^ 43 | "/d:sonar.branch.name="%APPVEYOR_REPO_BRANCH%"" ^ 44 | "/d:sonar.branch.target="!TARGET_BRANCH!"" 45 | ) 46 | ) 47 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/CurrentTimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.CommonLibraries 4 | { 5 | public static class CurrentTimeHelper 6 | { 7 | public static long CurrentTimeMillis() 8 | { 9 | var Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 10 | return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/HTTPHeader.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.CommonLibraries 3 | { 4 | public class HTTPHeader 5 | { 6 | public string authorizationApiKey { get; set; } 7 | public string splitSDKVersion { get; set; } 8 | public string splitSDKSpecVersion { get; set; } 9 | public string splitSDKMachineName { get; set; } 10 | public string splitSDKMachineIP { get; set; } 11 | public bool? SplitSDKImpressionsMode { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/HTTPResult.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Splitio.CommonLibraries 4 | { 5 | public class HTTPResult 6 | { 7 | public HttpStatusCode statusCode { get; set; } 8 | public string content { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/ISdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.CommonLibraries 4 | { 5 | public interface ISdkApiClient 6 | { 7 | Task ExecuteGet(string requestUri); 8 | 9 | Task ExecutePost(string requestUri, string data); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/PeriodicTaskFactory.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Logger; 2 | using Splitio.Services.Shared.Classes; 3 | using System; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Splitio.CommonLibraries 8 | { 9 | /// 10 | /// Factory class to create a periodic Task 11 | /// 12 | public static class PeriodicTaskFactory 13 | { 14 | private static ISplitLogger _log = WrapperAdapter.GetLogger(typeof(PeriodicTaskFactory)); 15 | 16 | /// 17 | /// Starts the periodic task. 18 | /// 19 | public static Task Start(Action action, int intervalInMilliseconds, CancellationToken cancelToken) 20 | { 21 | void mainAction() 22 | { 23 | MainPeriodicTaskAction(intervalInMilliseconds, cancelToken, action); 24 | } 25 | 26 | return Task.Factory.StartNew(mainAction, cancelToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); 27 | } 28 | 29 | /// 30 | /// Mains the periodic task action. 31 | /// 32 | private static void MainPeriodicTaskAction(int intervalInMilliseconds, CancellationToken cancelToken, Action wrapperAction) 33 | { 34 | // using a ManualResetEventSlim as it is more efficient in small intervals. 35 | // In the case where longer intervals are used, it will automatically use 36 | // a standard WaitHandle.... 37 | // see http://msdn.microsoft.com/en-us/library/vstudio/5hbefs30(v=vs.100).aspx 38 | using (ManualResetEventSlim periodResetEvent = new ManualResetEventSlim(false)) 39 | { 40 | while (true) 41 | { 42 | if (cancelToken.IsCancellationRequested) 43 | { 44 | break; 45 | } 46 | 47 | Task subTask = Task.Factory.StartNew(wrapperAction, cancelToken); 48 | 49 | try 50 | { 51 | periodResetEvent.Wait(intervalInMilliseconds, cancelToken); 52 | } 53 | catch (Exception ex) 54 | { 55 | _log.Debug(ex.Message); 56 | } 57 | finally 58 | { 59 | periodResetEvent.Reset(); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/Splitio-net-core/CommonLibraries/TypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace Splitio.CommonLibraries 5 | { 6 | public static class TypeConverter 7 | { 8 | private static readonly DateTime date = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); 9 | 10 | public static DateTime ToDateTime(this long timestamp) 11 | { 12 | var timestampTruncatedToMinutes = timestamp - timestamp % 60000; 13 | return date.AddMilliseconds(timestampTruncatedToMinutes); 14 | } 15 | 16 | public static DateTime? ToDateTime(this string timestampString) 17 | { 18 | long timestamp; 19 | if (long.TryParse(timestampString, out timestamp)) 20 | { 21 | return timestamp.ToDateTime(); 22 | } 23 | 24 | DateTime datetime; 25 | if (DateTime.TryParse(timestampString, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out datetime)) 26 | { 27 | return datetime; 28 | } 29 | 30 | return null; 31 | } 32 | 33 | public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan) 34 | { 35 | if (timeSpan == TimeSpan.Zero) 36 | { 37 | return dateTime; 38 | } 39 | return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/AdapterType.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Client.Classes 2 | { 3 | public enum AdapterType 4 | { 5 | Redis //Redis by default 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/AlgorithmEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public enum AlgorithmEnum 4 | { 5 | LegacyHash = 1, 6 | Murmur = 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/AttributeMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Evaluator; 2 | using Splitio.Services.Parsing; 3 | using System.Collections.Generic; 4 | 5 | namespace Splitio.Domain 6 | { 7 | public class AttributeMatcher 8 | { 9 | public string attribute { get; set; } 10 | public IMatcher matcher { get; set; } 11 | public bool negate { get; set; } 12 | 13 | public virtual bool Match(Key key, Dictionary attributes, IEvaluator evaluator = null) 14 | { 15 | if (attribute == null) 16 | { 17 | return (negate ^ matcher.Match(key, attributes, evaluator)); 18 | } 19 | 20 | if (attributes == null) 21 | { 22 | return false; 23 | } 24 | 25 | attributes.TryGetValue(attribute, out object value); 26 | 27 | if (value == null) 28 | { 29 | return false; 30 | } 31 | 32 | return (negate ^ matcher.Match(value, attributes, evaluator)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/AuthenticationResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class AuthenticationResponse 6 | { 7 | public bool? PushEnabled { get; set; } 8 | public string Token { get; set; } 9 | public string Channels { get; set; } 10 | public double? Expiration { get; set; } 11 | public bool? Retry { get; set; } 12 | } 13 | 14 | public class Jwt 15 | { 16 | [JsonProperty("x-ably-capability")] 17 | public string Capability { get; set; } 18 | [JsonProperty("x-ably-clientId")] 19 | public string ClientId { get; set; } 20 | [JsonProperty("exp")] 21 | public long Expiration { get; set; } 22 | [JsonProperty("iat")] 23 | public long IssuedAt { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/BaseConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class BaseConfig 4 | { 5 | public string SdkVersion { get; set; } 6 | public string SdkSpecVersion { get; set; } 7 | public string SdkMachineName { get; set; } 8 | public string SdkMachineIP { get; set; } 9 | public bool LabelsEnabled { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/BetweenData.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class BetweenData 5 | { 6 | public DataTypeEnum? dataType { get; set; } 7 | public long start { get; set; } 8 | public long end { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/CacheAdapterConfigurationOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Client.Classes 2 | { 3 | public class CacheAdapterConfigurationOptions 4 | { 5 | public AdapterType Type { get; set; } 6 | public string Host { get; set; } 7 | public string Port { get; set; } 8 | public string Password { get; set; } 9 | public int? Database { get; set; } 10 | public int? ConnectTimeout { get; set; } 11 | public int? ConnectRetry { get; set; } 12 | public int? SyncTimeout { get; set; } 13 | public string UserPrefix { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/CombinerEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public enum CombinerEnum 5 | { 6 | AND 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/CombiningMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Evaluator; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Splitio.Domain 6 | { 7 | public class CombiningMatcher 8 | { 9 | public CombinerEnum combiner { get; set; } 10 | public List delegates { get; set; } 11 | 12 | public virtual bool Match(Key key, Dictionary attributes, IEvaluator evaluator = null) 13 | { 14 | if (delegates == null || delegates.Count() == 0) 15 | { 16 | return false; 17 | } 18 | 19 | switch (combiner) 20 | { 21 | case CombinerEnum.AND: 22 | default: 23 | return delegates.All(matcher => matcher.Match(key, attributes, evaluator)); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ConditionDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class ConditionDefinition 6 | { 7 | public string conditionType { get; set; } 8 | public MatcherGroupDefinition matcherGroup { get; set; } 9 | public List partitions { get; set; } 10 | public string label { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ConditionType.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public enum ConditionType 4 | { 5 | WHITELIST, 6 | ROLLOUT 7 | } 8 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ConditionWithLogic.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class ConditionWithLogic 6 | { 7 | public ConditionType conditionType { get; set; } 8 | public CombiningMatcher matcher { get; set; } 9 | public List partitions { get; set; } 10 | public string label { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ConfigurationOptions.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Impressions.Interfaces; 3 | 4 | namespace Splitio.Services.Client.Classes 5 | { 6 | public class ConfigurationOptions 7 | { 8 | public Mode Mode { get; set; } 9 | public string Endpoint { get; set; } 10 | public string EventsEndpoint { get; set; } 11 | public string LocalhostFilePath { get; set; } 12 | public int? FeaturesRefreshRate { get; set; } 13 | public int? SegmentsRefreshRate { get; set; } 14 | public bool RandomizeRefreshRates { get; set; } 15 | public int? ImpressionsRefreshRate { get; set; } 16 | public int? MaxImpressionsLogSize { get; set; } 17 | public int? EventsFirstPushWindow { get; set; } 18 | public int? EventsPushRate { get; set; } 19 | public int? EventsQueueSize { get; set; } 20 | public long? ConnectionTimeout { get; set; } 21 | public long? ReadTimeout { get; set; } 22 | public int? MaxMetricsCountCallsBeforeFlush { get; set; } 23 | public int? MetricsRefreshRate { get; set; } 24 | public int? SplitsStorageConcurrencyLevel { get; set; } 25 | public string SdkMachineName { get; set; } 26 | public string SdkMachineIP { get; set; } 27 | public int? NumberOfParalellSegmentTasks { get; set; } 28 | public bool? LabelsEnabled { get; set; } 29 | public IImpressionListener ImpressionListener { get; set; } 30 | public CacheAdapterConfigurationOptions CacheAdapterConfig { get; set; } 31 | public bool? IPAddressesEnabled { get; set; } 32 | public bool? StreamingEnabled { get; set; } 33 | public int? AuthRetryBackoffBase { get; set; } 34 | public int? StreamingReconnectBackoffBase { get; set; } 35 | public string AuthServiceURL { get; set; } 36 | public string StreamingServiceURL { get; set; } 37 | public ImpressionsMode? ImpressionsMode { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Constans.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class Constans 4 | { 5 | public static string Unknown => "unknown"; 6 | public static string NA => "NA"; 7 | public static string Bearer => "Bearer"; 8 | public static int ProtocolTypeTls12 => 3072; 9 | public static string PushControlPri => "control_pri"; 10 | public static string PushControlSec => "control_sec"; 11 | public static string PushOccupancyPrefix => "[?occupancy=metrics.publishers]"; 12 | public static int PushSecondsBeforeExpiration => 600; // how many seconds prior to token expiration to trigger reauth 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/DataTypeEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public enum DataTypeEnum 5 | { 6 | NUMBER, 7 | DATETIME, 8 | STRING, 9 | SET 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/DependencyData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class DependencyData 6 | { 7 | public string split { get; set; } 8 | public List treatments { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Event.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class Event 6 | { 7 | public string key { get; set; } 8 | public string trafficTypeName { get; set; } 9 | public string eventTypeId { get; set; } 10 | public double? value { get; set; } 11 | public long timestamp { get; set; } 12 | public Dictionary properties { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/EventValidatorResult.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class EventValidatorResult 4 | { 5 | public bool Success { get; set; } 6 | public object Value { get; set; } 7 | public long EventSize { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ImpressionsMode.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public enum ImpressionsMode 4 | { 5 | Optimized, 6 | Debug 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Key.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class Key 5 | { 6 | public string matchingKey { get; private set; } 7 | public string bucketingKey { get; private set; } 8 | public bool bucketingKeyHadValue { get; private set; } 9 | 10 | public Key(string matchingKey, string bucketingKey) 11 | { 12 | this.matchingKey = matchingKey; 13 | this.bucketingKeyHadValue = bucketingKey != null; 14 | this.bucketingKey = bucketingKey ?? matchingKey; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/KeyImpression.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class KeyImpression 6 | { 7 | public KeyImpression() { } 8 | 9 | public KeyImpression(string matchingKey, string feature, string treatment, long time, long? changeNumber, string label, string bucketingKey, long? previousTime = null, bool optimized = false) 10 | { 11 | this.feature = feature; 12 | keyName = matchingKey; 13 | this.treatment = treatment; 14 | this.time = time; 15 | this.changeNumber = changeNumber; 16 | this.label = label; 17 | this.bucketingKey = bucketingKey; 18 | this.previousTime = previousTime; 19 | Optimized = optimized; 20 | } 21 | 22 | [JsonIgnore] 23 | public string feature { get; set; } 24 | public string keyName { get; set; } 25 | public string treatment { get; set; } 26 | public long time { get; set; } 27 | public long? changeNumber { get; set; } 28 | public string label { get; set; } 29 | public string bucketingKey { get; set; } 30 | public long? previousTime { get; set; } 31 | [JsonIgnore] 32 | public bool Optimized { get; set; } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/KeySelector.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class KeySelector 5 | { 6 | public string trafficType { get; set; } 7 | public string attribute { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Labels.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class Labels 4 | { 5 | public static string Killed => "killed"; 6 | public static string DefaultRule => "default rule"; 7 | public static string SplitNotFound => "definition not found"; 8 | public static string Exception => "exception"; 9 | public static string TrafficAllocationFailed => "not in split"; 10 | public static string ClientNotReady => "not ready"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/LightSplit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class SplitView 6 | { 7 | public string name { get; set; } 8 | public string trafficType { get; set; } 9 | public bool killed { get; set; } 10 | public List treatments { get; set; } 11 | public long changeNumber { get; set; } 12 | public Dictionary configs { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/MatcherDefinition.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class MatcherDefinition 5 | { 6 | public KeySelector keySelector { get; set; } 7 | public string matcherType { get; set; } 8 | public bool negate { get; set; } 9 | public UserDefinedSegmentData userDefinedSegmentMatcherData { get; set; } 10 | public WhitelistData whitelistMatcherData { get; set; } 11 | public UnaryNumericData unaryNumericMatcherData { get; set; } 12 | public BetweenData betweenMatcherData { get; set; } 13 | public DependencyData dependencyMatcherData { get; set; } 14 | public bool? booleanMatcherData { get; set; } 15 | public string stringMatcherData { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/MatcherGroupDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class MatcherGroupDefinition 6 | { 7 | public string combiner { get; set; } 8 | public List matchers {get; set;} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/MatcherTypeEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public enum MatcherTypeEnum 5 | { 6 | ALL_KEYS, 7 | IN_SEGMENT, 8 | WHITELIST, 9 | EQUAL_TO, 10 | GREATER_THAN_OR_EQUAL_TO, 11 | LESS_THAN_OR_EQUAL_TO, 12 | BETWEEN, 13 | EQUAL_TO_SET, 14 | CONTAINS_ANY_OF_SET, 15 | CONTAINS_ALL_OF_SET, 16 | PART_OF_SET, 17 | STARTS_WITH, 18 | ENDS_WITH, 19 | CONTAINS_STRING, 20 | IN_SPLIT_TREATMENT, 21 | EQUAL_TO_BOOLEAN, 22 | MATCHES_STRING 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Mode.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Client.Classes 2 | { 3 | public enum Mode 4 | { 5 | Standalone, 6 | Consumer, 7 | Producer 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/MultipleEvaluatorResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class MultipleEvaluatorResult 6 | { 7 | public Dictionary TreatmentResults { get; set; } 8 | public long ElapsedMilliseconds { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Operations.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class Operations 4 | { 5 | public static string SdkGetTreatment => "sdk.getTreatment"; 6 | public static string SdkGetTreatments => "sdk.getTreatments"; 7 | public static string SdkGetTreatmentWithConfig => "sdk.getTreatmentWithConfig"; 8 | public static string SdkGetTreatmentsWithConfig => "sdk.getTreatmentsWithConfig"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ParsedSplit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class ParsedSplit : SplitBase 6 | { 7 | public List conditions { get; set; } 8 | public AlgorithmEnum algo { get; set; } 9 | public int trafficAllocationSeed { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/PartitionDefinition.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class PartitionDefinition 5 | { 6 | public string treatment { get; set; } 7 | public int size { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ReadConfigData.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class ReadConfigData 4 | { 5 | public string SdkVersion { get; set; } 6 | public string SdkSpecVersion { get; set; } 7 | public string SdkMachineName { get; set; } 8 | public string SdkMachineIP { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Segment.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.SegmentFetcher.Interfaces; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | 5 | namespace Splitio.Domain 6 | { 7 | public class Segment: ISegment 8 | { 9 | private string name; 10 | public long changeNumber { get; set; } 11 | //ConcurrentDictionary with no value is the concurrent alternative for HashSet 12 | private ConcurrentDictionary keys; 13 | 14 | public Segment(string name, long changeNumber = -1, ConcurrentDictionary keys= null) 15 | { 16 | this.name = name; 17 | this.changeNumber = changeNumber; 18 | this.keys = keys ?? new ConcurrentDictionary(); 19 | } 20 | 21 | public void AddKeys(List keys) 22 | { 23 | if (keys != null) 24 | { 25 | foreach (var key in keys) 26 | { 27 | this.keys.TryAdd(key, 0); 28 | } 29 | } 30 | } 31 | 32 | public void RemoveKeys(List keys) 33 | { 34 | if (keys != null) 35 | { 36 | foreach (var key in keys) 37 | { 38 | byte value; 39 | this.keys.TryRemove(key, out value); 40 | } 41 | } 42 | } 43 | 44 | public bool Contains(string key) 45 | { 46 | byte value; 47 | return keys.TryGetValue(key, out value); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/SegmentChange.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class SegmentChange 6 | { 7 | public string name { get; set; } 8 | public long since { get; set; } 9 | public long till { get; set; } 10 | public List added { get; set; } 11 | public List removed { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/SelfRefreshingConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class SelfRefreshingConfig : BaseConfig 4 | { 5 | public string BaseUrl { get; set; } 6 | public string EventsBaseUrl { get; set; } 7 | public int SplitsRefreshRate { get; set; } 8 | public int SegmentRefreshRate { get; set; } 9 | public long HttpConnectionTimeout { get; set; } 10 | public long HttpReadTimeout { get; set; } 11 | public int ConcurrencyLevel { get; set; } 12 | public int TreatmentLogRefreshRate { get; set; } 13 | public int TreatmentLogSize { get; set; } 14 | public int EventsFirstPushWindow { get; set; } 15 | public int EventLogRefreshRate { get; set; } 16 | public int EventLogSize { get; set; } 17 | public int MaxCountCalls { get; set; } 18 | public int MaxTimeBetweenCalls { get; set; } 19 | public int NumberOfParalellSegmentTasks { get; set; } 20 | public bool RandomizeRefreshRates { get; set; } 21 | public bool StreamingEnabled { get; set; } 22 | public int AuthRetryBackoffBase { get; set; } 23 | public int StreamingReconnectBackoffBase { get; set; } 24 | public string AuthServiceURL { get; set; } 25 | public string StreamingServiceURL { get; set; } 26 | public ImpressionsMode ImpressionsMode { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/Split.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class Split : SplitBase 6 | { 7 | public string status { get; set; } 8 | public List conditions { get; set; } 9 | public int? algo { get; set; } 10 | public int? trafficAllocationSeed { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/SplitBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public abstract class SplitBase 6 | { 7 | public string name { get; set; } 8 | public int seed { get; set; } 9 | public bool killed { get; set; } 10 | public string defaultTreatment { get; set; } 11 | public long changeNumber { get; set; } 12 | public string trafficTypeName { get; set; } 13 | public int trafficAllocation { get; set; } 14 | public Dictionary configurations { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/SplitChange.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class SplitChangesResult 6 | { 7 | public long since { get; set; } 8 | public long till { get; set; } 9 | public List splits { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/SplitResult.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class SplitResult 4 | { 5 | public string Treatment { get; set; } 6 | public string Config { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/StatusEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public enum StatusEnum 5 | { 6 | ACTIVE, 7 | ARCHIVED 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/TreatmentResult.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class TreatmentResult 4 | { 5 | public string Label { get; set; } 6 | public string Treatment { get; set; } 7 | public long? ChangeNumber { get; set; } 8 | public string Config { get; set; } 9 | public long ElapsedMilliseconds { get; set; } 10 | 11 | public TreatmentResult(string label, string treatment, long? changeNumber = null, string config = null, long? elapsedMilliseconds = null) 12 | { 13 | Label = label; 14 | Treatment = treatment; 15 | ChangeNumber = changeNumber; 16 | Config = config; 17 | ElapsedMilliseconds = elapsedMilliseconds ?? 0; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/UnaryNumericData.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class UnaryNumericData 5 | { 6 | public DataTypeEnum? dataType { get; set; } 7 | public long value { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/UserDefinedSegmentData.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Splitio.Domain 3 | { 4 | public class UserDefinedSegmentData 5 | { 6 | public string segmentName { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/ValidatorResult.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class ValidatorResult 4 | { 5 | public bool Success { get; set; } 6 | public string Value { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/WhiteListData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Domain 4 | { 5 | public class WhitelistData 6 | { 7 | public List whitelist { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Domain/WrappedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Domain 2 | { 3 | public class WrappedEvent 4 | { 5 | public Event Event { get; set; } 6 | public long Size { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Splitio_net_core")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("3db60285-e48f-4dcc-ad15-0d11f79c3dd4")] 20 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Cache/Interfaces/IMetricsCache.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Metrics.Classes; 2 | using Splitio.Services.Metrics.Interfaces; 3 | using System.Collections.Generic; 4 | 5 | namespace Splitio.Services.Cache.Interfaces 6 | { 7 | public interface IMetricsCache 8 | { 9 | Counter GetCount(string name); 10 | 11 | Counter IncrementCount(string name, long delta); 12 | 13 | Dictionary FetchAllCountersAndClear(); 14 | 15 | void SetGauge(string name, long gauge); 16 | 17 | long GetGauge(string name); 18 | 19 | Dictionary FetchAllGaugesAndClear(); 20 | 21 | ILatencyTracker GetLatencyTracker(string name); 22 | 23 | void SetLatency(string name, long value); 24 | 25 | Dictionary FetchAllLatencyTrackersAndClear(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Cache/Interfaces/IReadinessGatesCache.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Cache.Interfaces 2 | { 3 | public interface IReadinessGatesCache 4 | { 5 | bool AreSegmentsReady(int milliseconds); 6 | 7 | bool AreSplitsReady(int milliseconds); 8 | 9 | bool IsSDKReady(int milliseconds); 10 | 11 | bool RegisterSegment(string segmentName); 12 | 13 | void SegmentIsReady(string segmentName); 14 | 15 | void SplitsAreReady(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Cache/Interfaces/ISegmentCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Services.Cache.Interfaces 4 | { 5 | public interface ISegmentCache 6 | { 7 | void AddToSegment(string segmentName, List segmentKeys); 8 | 9 | void RemoveFromSegment(string segmentName, List segmentKeys); 10 | 11 | bool IsInSegment(string segmentName, string key); 12 | 13 | void SetChangeNumber(string segmentName, long changeNumber); 14 | 15 | long GetChangeNumber(string segmentName); 16 | 17 | void Clear(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Cache/Interfaces/ISplitCache.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Cache.Interfaces 5 | { 6 | public interface ISplitCache 7 | { 8 | void AddSplit(string splitName, SplitBase split); 9 | 10 | bool RemoveSplit(string splitName); 11 | 12 | bool AddOrUpdate(string splitName, SplitBase split); 13 | 14 | void SetChangeNumber(long changeNumber); 15 | 16 | long GetChangeNumber(); 17 | 18 | ParsedSplit GetSplit(string splitName); 19 | 20 | List GetAllSplits(); 21 | 22 | void Clear(); 23 | 24 | bool TrafficTypeExists(string trafficType); 25 | 26 | List FetchMany(List splitNames); 27 | 28 | void Kill(long changeNumber, string splitName, string defaultTreatment); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Client/Interfaces/ISplitClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Client.Interfaces 5 | { 6 | public interface ISplitClient 7 | { 8 | ISplitManager GetSplitManager(); 9 | string GetTreatment(string key, string feature, Dictionary attributes = null); 10 | string GetTreatment(Key key, string feature, Dictionary attributes = null); 11 | SplitResult GetTreatmentWithConfig(string key, string feature, Dictionary attributes = null); 12 | SplitResult GetTreatmentWithConfig(Key key, string feature, Dictionary attributes = null); 13 | Dictionary GetTreatments(string key, List features, Dictionary attributes = null); 14 | Dictionary GetTreatments(Key key, List features, Dictionary attributes = null); 15 | Dictionary GetTreatmentsWithConfig(string key, List features, Dictionary attributes = null); 16 | Dictionary GetTreatmentsWithConfig(Key key, List features, Dictionary attributes = null); 17 | bool Track(string key, string trafficType, string eventType, double? value = null, Dictionary properties = null); 18 | void Destroy(); 19 | bool IsDestroyed(); 20 | void BlockUntilReady(int blockMilisecondsUntilReady); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Client/Interfaces/ISplitFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Client.Interfaces 2 | { 3 | public interface ISplitFactory 4 | { 5 | ISplitClient Client(); 6 | ISplitManager Manager(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Client/Interfaces/ISplitManager.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Client.Interfaces 5 | { 6 | public interface ISplitManager 7 | { 8 | List Splits(); 9 | 10 | List SplitNames(); 11 | 12 | SplitView Split(string featureName); 13 | 14 | void BlockUntilReady(int blockMilisecondsUntilReady); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/BackOff.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.Common 4 | { 5 | public class BackOff : IBackOff 6 | { 7 | private readonly int _backOffBase; 8 | private int _attempt; 9 | 10 | public BackOff(int backOffBase, int attempt = 0) 11 | { 12 | _backOffBase = backOffBase; 13 | _attempt = attempt; 14 | } 15 | 16 | public int GetAttempt() 17 | { 18 | return _attempt; 19 | } 20 | 21 | public double GetInterval() 22 | { 23 | var interval = 0d; 24 | 25 | if (_attempt > 0) 26 | { 27 | interval = _backOffBase * Math.Pow(2, _attempt); 28 | } 29 | 30 | _attempt++; 31 | 32 | return interval; 33 | } 34 | 35 | public void Reset() 36 | { 37 | _attempt = 0; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/IAuthApiClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Threading.Tasks; 3 | 4 | namespace Splitio.Services.Common 5 | { 6 | public interface IAuthApiClient 7 | { 8 | Task AuthenticateAsync(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/IBackOff.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Common 2 | { 3 | public interface IBackOff 4 | { 5 | double GetInterval(); 6 | void Reset(); 7 | int GetAttempt(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/IPushManager.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.Common 4 | { 5 | public interface IPushManager 6 | { 7 | Task StartSse(); 8 | void StopSse(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/ISplitioHttpClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Splitio.Services.Common 8 | { 9 | public interface ISplitioHttpClient : IDisposable 10 | { 11 | Task GetAsync(string url); 12 | Task GetAsync(string url, HttpCompletionOption completionOption, CancellationToken cancellationToken); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/ISyncManager.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Common 2 | { 3 | public interface ISyncManager 4 | { 5 | void Start(); 6 | void Shutdown(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Common/ISynchronizer.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.Common 4 | { 5 | public interface ISynchronizer 6 | { 7 | void SyncAll(); 8 | Task SynchronizeSplits(); 9 | Task SynchronizeSegment(string segmentName); 10 | void StartPeriodicFetching(); 11 | void StopPeriodicFetching(); 12 | void StartPeriodicDataRecording(); 13 | void StopPeriodicDataRecording(); 14 | void ClearFetchersCache(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EngineEvaluator/ISplitter.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.EngineEvaluator 5 | { 6 | public interface ISplitter 7 | { 8 | string GetTreatment(string key, int seed, List partitions, AlgorithmEnum algorithm); 9 | int GetBucket(string key, int seed, AlgorithmEnum algorithm); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Evaluator/IEvaluator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Evaluator 5 | { 6 | public interface IEvaluator 7 | { 8 | TreatmentResult EvaluateFeature(Key key, string featureName, Dictionary attributes = null); 9 | MultipleEvaluatorResult EvaluateFeatures(Key key, List featureNames, Dictionary attributes = null); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/EventReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public class EventReceivedEventArgs : EventArgs 6 | { 7 | public IncomingNotification Event { get; } 8 | 9 | public EventReceivedEventArgs(IncomingNotification incomingNotification) 10 | { 11 | Event = incomingNotification; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/FeedbackEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public class SSEActionsEventArgs : EventArgs 6 | { 7 | public SSEClientActions Action { get; } 8 | 9 | public SSEActionsEventArgs(SSEClientActions action) 10 | { 11 | Action = action; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/IEventSourceClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public interface IEventSourceClient 6 | { 7 | bool ConnectAsync(string url); 8 | void Disconnect(SSEClientActions action = SSEClientActions.DISCONNECT); 9 | bool IsConnected(); 10 | 11 | event EventHandler EventReceived; 12 | event EventHandler ActionEvent; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/INotificationManagerKeeper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public interface INotificationManagerKeeper 6 | { 7 | void HandleIncomingEvent(IncomingNotification notification); 8 | 9 | event EventHandler ActionEvent; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/INotificationParser.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource 2 | { 3 | public interface INotificationParser 4 | { 5 | IncomingNotification Parse(string notificationString); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/INotificationProcessor.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource 2 | { 3 | public interface INotificationProcessor 4 | { 5 | void Proccess(IncomingNotification notification); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/ISSEHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public interface ISSEHandler 6 | { 7 | bool Start(string token, string channels); 8 | void Stop(); 9 | void StartWorkers(); 10 | void StopWorkers(); 11 | 12 | event EventHandler ActionEvent; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/Notification.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource 2 | { 3 | public class Notification 4 | { 5 | public string Id { get; set; } 6 | public string Event { get; set; } 7 | public NotificationData Data { get; set; } 8 | } 9 | 10 | public class NotificationData 11 | { 12 | public string Id { get; set; } 13 | public string Channel { get; set; } 14 | public string Data { get; set; } 15 | } 16 | 17 | public enum NotificationType 18 | { 19 | SPLIT_UPDATE, 20 | SPLIT_KILL, 21 | SEGMENT_UPDATE, 22 | CONTROL, 23 | OCCUPANCY, 24 | ERROR 25 | } 26 | 27 | public enum ControlType 28 | { 29 | STREAMING_PAUSED, 30 | STREAMING_RESUMED, 31 | STREAMING_DISABLED 32 | } 33 | 34 | public class IncomingNotification 35 | { 36 | public NotificationType Type { get; set; } 37 | public string Channel { get; set; } 38 | } 39 | 40 | public class NotificationError : IncomingNotification 41 | { 42 | public string Message { get; set; } 43 | public int StatusCode { get; set; } 44 | public int Code { get; set; } 45 | } 46 | 47 | public class SplitChangeNotifiaction : IncomingNotification 48 | { 49 | public long ChangeNumber { get; set; } 50 | } 51 | 52 | public class SplitKillNotification : IncomingNotification 53 | { 54 | public long ChangeNumber { get; set; } 55 | public string DefaultTreatment { get; set; } 56 | public string SplitName { get; set; } 57 | } 58 | 59 | public class SegmentChangeNotification : IncomingNotification 60 | { 61 | public long ChangeNumber { get; set; } 62 | public string SegmentName { get; set; } 63 | } 64 | 65 | public class ControlNotification : IncomingNotification 66 | { 67 | public ControlType ControlType { get; set; } 68 | } 69 | 70 | public class OccupancyNotification : IncomingNotification 71 | { 72 | public OccupancyMetricsData Metrics { get; set; } 73 | } 74 | 75 | public class OccupancyMetricsData 76 | { 77 | public int Publishers { get; set; } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/NotificationProcessor.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.EventSource.Workers; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Shared.Classes; 4 | using System; 5 | 6 | namespace Splitio.Services.EventSource 7 | { 8 | public class NotificationProcessor : INotificationProcessor 9 | { 10 | private readonly ISplitLogger _log; 11 | private readonly ISplitsWorker _splitsWorker; 12 | private readonly ISegmentsWorker _segmentsWorker; 13 | 14 | public NotificationProcessor(ISplitsWorker splitsWorker, 15 | ISegmentsWorker segmentsWorker, 16 | ISplitLogger log = null) 17 | { 18 | _log = log ?? WrapperAdapter.GetLogger(typeof(EventSourceClient)); 19 | _splitsWorker = splitsWorker; 20 | _segmentsWorker = segmentsWorker; 21 | } 22 | 23 | public void Proccess(IncomingNotification notification) 24 | { 25 | try 26 | { 27 | switch (notification.Type) 28 | { 29 | case NotificationType.SPLIT_UPDATE: 30 | var scn = (SplitChangeNotifiaction)notification; 31 | _splitsWorker.AddToQueue(scn.ChangeNumber); 32 | break; 33 | case NotificationType.SPLIT_KILL: 34 | var skn = (SplitKillNotification)notification; 35 | _splitsWorker.KillSplit(skn.ChangeNumber, skn.SplitName, skn.DefaultTreatment); 36 | _splitsWorker.AddToQueue(skn.ChangeNumber); 37 | break; 38 | case NotificationType.SEGMENT_UPDATE: 39 | var sc = (SegmentChangeNotification)notification; 40 | _segmentsWorker.AddToQueue(sc.ChangeNumber, sc.SegmentName); 41 | break; 42 | default: 43 | _log.Debug($"Incorrect Event type: {notification}"); 44 | break; 45 | } 46 | } 47 | catch (Exception ex) 48 | { 49 | _log.Error($"Processor: {ex.Message}"); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/ReadStreamException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.EventSource 4 | { 5 | public class ReadStreamException : Exception 6 | { 7 | public SSEClientActions Action { get; set; } 8 | 9 | public ReadStreamException(SSEClientActions action, string message) 10 | : base(message) 11 | { 12 | Action = action; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/SSEClientActions.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource 2 | { 3 | public enum SSEClientActions 4 | { 5 | CONNECTED, 6 | DISCONNECT, 7 | RETRYABLE_ERROR, 8 | NONRETRYABLE_ERROR, 9 | SUBSYSTEM_DOWN, 10 | SUBSYSTEM_READY, 11 | SUBSYSTEM_OFF 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/Workers/ISegmentsWorker.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource.Workers 2 | { 3 | public interface ISegmentsWorker : IWorker 4 | { 5 | void AddToQueue(long changeNumber, string segmentName); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/Workers/ISplitsWorker.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource.Workers 2 | { 3 | public interface ISplitsWorker : IWorker 4 | { 5 | void AddToQueue(long changeNumber); 6 | void KillSplit(long changeNumber, string splitName, string defaultTreatment); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/Workers/IWorker.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource.Workers 2 | { 3 | public interface IWorker 4 | { 5 | void Start(); 6 | void Stop(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/EventSource/Workers/SegmentQueueDto.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.EventSource.Workers 2 | { 3 | public class SegmentQueueDto 4 | { 5 | public long ChangeNumber { get; set; } 6 | public string SegmentName { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Events/Classes/EventSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.CommonLibraries; 3 | using Splitio.Domain; 4 | using Splitio.Services.Events.Interfaces; 5 | using Splitio.Services.Logger; 6 | using Splitio.Services.Shared.Classes; 7 | using System.Collections.Generic; 8 | using System.Net; 9 | 10 | namespace Splitio.Services.Events.Classes 11 | { 12 | public class EventSdkApiClient : SdkApiClient, IEventSdkApiClient 13 | { 14 | private const string EventsUrlTemplate = "/api/events/bulk"; 15 | 16 | private static readonly ISplitLogger Log = WrapperAdapter.GetLogger(typeof(EventSdkApiClient)); 17 | 18 | public EventSdkApiClient(HTTPHeader header, string baseUrl, long connectionTimeOut, long readTimeout) 19 | : base(header, baseUrl, connectionTimeOut, readTimeout) 20 | { } 21 | 22 | public async void SendBulkEvents(List events) 23 | { 24 | var eventsJson = JsonConvert.SerializeObject(events, new JsonSerializerSettings 25 | { 26 | NullValueHandling = NullValueHandling.Ignore 27 | }); 28 | 29 | var response = await ExecutePost(EventsUrlTemplate, eventsJson); 30 | 31 | if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous) 32 | { 33 | Log.Error(string.Format("Http status executing SendBulkEvents: {0} - {1}", response.statusCode.ToString(), response.content)); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Events/Interfaces/IEventSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Events.Interfaces 5 | { 6 | public interface IEventSdkApiClient 7 | { 8 | void SendBulkEvents(List events); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Events/Interfaces/IEventsLog.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.Events.Interfaces 4 | { 5 | public interface IEventsLog 6 | { 7 | void Start(); 8 | void Stop(); 9 | void Log(WrappedEvent wrappedEvent); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Classes/ImpressionHasher.cs: -------------------------------------------------------------------------------- 1 | using Murmur; 2 | using Splitio.Domain; 3 | using Splitio.Services.Impressions.Interfaces; 4 | using System; 5 | using System.Text; 6 | 7 | namespace Splitio.Services.Impressions.Classes 8 | { 9 | public class ImpressionHasher : IImpressionHasher 10 | { 11 | public ulong Process(KeyImpression impression) 12 | { 13 | var key = $"{UnknowIfNull(impression.keyName)}:{UnknowIfNull(impression.feature)}:{UnknowIfNull(impression.treatment)}:{UnknowIfNull(impression.label)}:{ZeroIfNull(impression.changeNumber)}"; 14 | 15 | return Hash(key, 0); 16 | } 17 | 18 | public ulong Hash(string key, uint seed) 19 | { 20 | Murmur128 murmur128 = MurmurHash.Create128(seed: seed, preference: AlgorithmPreference.X64); 21 | byte[] keyToBytes = Encoding.ASCII.GetBytes(key); 22 | byte[] seedResult = murmur128.ComputeHash(keyToBytes); 23 | 24 | return BitConverter.ToUInt64(seedResult, 0); 25 | } 26 | 27 | private string UnknowIfNull(string value) 28 | { 29 | return string.IsNullOrEmpty(value) ? "UNKNOWN" : value; 30 | } 31 | 32 | private long ZeroIfNull(long? value) 33 | { 34 | return value == null ? 0 : value.Value; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Classes/ImpressionsCountSender.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Services.Impressions.Interfaces; 3 | using Splitio.Services.Logger; 4 | using Splitio.Services.Shared.Classes; 5 | using System; 6 | using System.Threading; 7 | 8 | namespace Splitio.Services.Impressions.Classes 9 | { 10 | public class ImpressionsCountSender : IImpressionsCountSender 11 | { 12 | // Send bulk impressions count - Refresh rate: 30 min. 13 | private const int CounterRefreshRateSeconds = 1800; 14 | 15 | protected static readonly ISplitLogger Logger = WrapperAdapter.GetLogger(typeof(ImpressionsCountSender)); 16 | 17 | private readonly ITreatmentSdkApiClient _apiClient; 18 | private readonly IImpressionsCounter _impressionsCounter; 19 | private readonly CancellationTokenSource _cancellationTokenSource; 20 | private readonly int _interval; 21 | 22 | private bool _running; 23 | 24 | public ImpressionsCountSender(ITreatmentSdkApiClient apiClient, 25 | IImpressionsCounter impressionsCounter, 26 | int? interval = null) 27 | { 28 | _apiClient = apiClient; 29 | _impressionsCounter = impressionsCounter; 30 | _cancellationTokenSource = new CancellationTokenSource(); 31 | _interval = interval ?? CounterRefreshRateSeconds; 32 | _running = false; 33 | } 34 | 35 | public void Start() 36 | { 37 | PeriodicTaskFactory.Start(() => { SendBulkImpressionsCount(); _running = true; }, CounterRefreshRateSeconds * 1000, _cancellationTokenSource.Token); 38 | } 39 | 40 | public void Stop() 41 | { 42 | if (!_running) 43 | { 44 | return; 45 | } 46 | 47 | _cancellationTokenSource.Cancel(); 48 | SendBulkImpressionsCount(); 49 | } 50 | 51 | private void SendBulkImpressionsCount() 52 | { 53 | var impressions = _impressionsCounter.PopAll(); 54 | 55 | if (impressions.Count > 0) 56 | { 57 | try 58 | { 59 | _apiClient.SendBulkImpressionsCount(impressions); 60 | } 61 | catch (Exception e) 62 | { 63 | Logger.Error("Exception caught sending impressions count.", e); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Classes/ImpressionsCounter.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Impressions.Interfaces; 2 | using System; 3 | using System.Collections.Concurrent; 4 | 5 | namespace Splitio.Services.Impressions.Classes 6 | { 7 | public class ImpressionsCounter : IImpressionsCounter 8 | { 9 | private const int DefaultAmount = 1; 10 | 11 | private readonly ConcurrentDictionary _cache; 12 | 13 | public ImpressionsCounter() 14 | { 15 | _cache = new ConcurrentDictionary(); 16 | } 17 | 18 | public void Inc(string splitName, long timeFrame) 19 | { 20 | var key = new KeyCache(splitName, timeFrame); 21 | 22 | _cache.AddOrUpdate(key, DefaultAmount, (keyCache, cacheAmount) => cacheAmount + DefaultAmount); 23 | } 24 | 25 | public ConcurrentDictionary PopAll() 26 | { 27 | var values = new ConcurrentDictionary(_cache); 28 | 29 | _cache.Clear(); 30 | 31 | return values; 32 | } 33 | } 34 | 35 | public class KeyCache 36 | { 37 | public string SplitName { get; set; } 38 | public long TimeFrame { get; set; } 39 | 40 | public KeyCache(string splitName, long timeFrame) 41 | { 42 | SplitName = splitName; 43 | TimeFrame = ImpressionsHelper.TruncateTimeFrame(timeFrame); 44 | } 45 | 46 | public override int GetHashCode() 47 | { 48 | return Tuple.Create(SplitName, TimeFrame).GetHashCode(); 49 | } 50 | 51 | public override bool Equals(object obj) 52 | { 53 | if (this == obj) return true; 54 | if (obj == null || obj.GetType() != GetType()) return false; 55 | 56 | var key = (KeyCache)obj; 57 | return key.SplitName.Equals(SplitName) && key.TimeFrame.Equals(TimeFrame); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Classes/ImpressionsHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.Impressions.Classes 4 | { 5 | public class ImpressionsHelper 6 | { 7 | public const long TimeIintervalMs = 3600L * 1000L; 8 | 9 | public static long TruncateTimeFrame(long timestampInMs) 10 | { 11 | return timestampInMs - (timestampInMs % TimeIintervalMs); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Classes/ImpressionsObserver.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Lru; 3 | using Splitio.Services.Impressions.Interfaces; 4 | using System; 5 | 6 | namespace Splitio.Services.Impressions.Classes 7 | { 8 | public class ImpressionsObserver : IImpressionsObserver 9 | { 10 | private const int DefaultCacheSize = 500000; 11 | 12 | private readonly LruCache _cache; 13 | private readonly IImpressionHasher _impressionHasher; 14 | 15 | public ImpressionsObserver(IImpressionHasher impressionHasher) 16 | { 17 | _impressionHasher = impressionHasher; 18 | 19 | _cache = new LruCache(DefaultCacheSize); 20 | } 21 | 22 | public long? TestAndSet(KeyImpression impression) 23 | { 24 | long? defaultReturn = null; 25 | 26 | if (impression == null) 27 | { 28 | return defaultReturn; 29 | } 30 | 31 | ulong hash = _impressionHasher.Process(impression); 32 | 33 | try 34 | { 35 | long? previous = _cache.Get(hash); 36 | _cache.AddOrUpdate(hash, impression.time); 37 | 38 | return Math.Min(previous.Value, impression.time); 39 | } 40 | catch (Exception) 41 | { 42 | _cache.AddOrUpdate(hash, impression.time); 43 | 44 | return defaultReturn; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionHasher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.Impressions.Interfaces 4 | { 5 | public interface IImpressionHasher 6 | { 7 | ulong Process(KeyImpression impression); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionListener.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.Impressions.Interfaces 4 | { 5 | public interface IImpressionListener 6 | { 7 | void Log(KeyImpression impression); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionsCountSender.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Impressions.Interfaces 2 | { 3 | public interface IImpressionsCountSender 4 | { 5 | void Start(); 6 | void Stop(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionsCounter.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Impressions.Classes; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Splitio.Services.Impressions.Interfaces 5 | { 6 | public interface IImpressionsCounter 7 | { 8 | void Inc(string splitName, long timeFrame); 9 | ConcurrentDictionary PopAll(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionsLog.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Impressions.Interfaces 5 | { 6 | public interface IImpressionsLog 7 | { 8 | void Start(); 9 | void Stop(); 10 | void Log(IList impressions); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionsManager.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.Impressions.Interfaces 5 | { 6 | public interface IImpressionsManager 7 | { 8 | KeyImpression BuildImpression(string matchingKey, string feature, string treatment, long time, long? changeNumber, string label, string bucketingKey); 9 | void Track(List impressions); 10 | void BuildAndTrack(string matchingKey, string feature, string treatment, long time, long? changeNumber, string label, string bucketingKey); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/IImpressionsObserver.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.Impressions.Interfaces 4 | { 5 | public interface IImpressionsObserver 6 | { 7 | long? TestAndSet(KeyImpression impression); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Impressions/Interfaces/ITreatmentSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Impressions.Classes; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Services.Impressions.Interfaces 7 | { 8 | public interface ITreatmentSdkApiClient 9 | { 10 | void SendBulkImpressions(List impressions); 11 | void SendBulkImpressionsCount(ConcurrentDictionary impressionsCount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Classes/ApiKeyValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.InputValidation.Interfaces; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Shared.Classes; 4 | 5 | namespace Splitio.Services.InputValidation.Classes 6 | { 7 | public class ApiKeyValidator : IApiKeyValidator 8 | { 9 | protected readonly ISplitLogger _log; 10 | 11 | public ApiKeyValidator(ISplitLogger log = null) 12 | { 13 | _log = log ?? WrapperAdapter.GetLogger(typeof(ApiKeyValidator)); 14 | } 15 | 16 | public void Validate(string apiKey) 17 | { 18 | if (apiKey == string.Empty) 19 | { 20 | _log.Error("factory instantiation: you passed and empty api_key, api_key must be a non-empty string."); 21 | } 22 | 23 | if (apiKey == null) 24 | { 25 | _log.Error("factory instantiation: you passed a null api_key, api_key must be a non-empty string."); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Classes/EventTypeValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.InputValidation.Interfaces; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Shared.Classes; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace Splitio.Services.InputValidation.Classes 7 | { 8 | public class EventTypeValidator : IEventTypeValidator 9 | { 10 | private const string REGEX = "^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$"; 11 | 12 | protected readonly ISplitLogger _log; 13 | 14 | public EventTypeValidator(ISplitLogger log = null) 15 | { 16 | _log = log ?? WrapperAdapter.GetLogger(typeof(EventTypeValidator)); 17 | } 18 | 19 | public bool IsValid(string eventType, string method) 20 | { 21 | if (eventType == string.Empty) 22 | { 23 | _log.Error($"{method}: you passed an empty event_type, event_type must be a non-empty String"); 24 | return false; 25 | } 26 | 27 | if (eventType == null) 28 | { 29 | _log.Error($"{method}: you passed a null event_type, event_type must be a non-empty String"); 30 | return false; 31 | } 32 | 33 | if (!Regex.Match(eventType, REGEX).Success) 34 | { 35 | _log.Error($"{method}: you passed {eventType}, event name must adhere to the regular expression {REGEX}. This means an event name must be alphanumeric, cannot be more than 80 characters long, and can only include a dash, underscore, period, or colon as separators of alphanumeric characters"); 36 | return false; 37 | } 38 | 39 | return true; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Classes/KeyValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.InputValidation.Interfaces; 3 | using Splitio.Services.Logger; 4 | using Splitio.Services.Shared.Classes; 5 | 6 | namespace Splitio.Services.InputValidation.Classes 7 | { 8 | public class KeyValidator : IKeyValidator 9 | { 10 | private const int KEY_MAX_LENGTH = 250; 11 | 12 | protected readonly ISplitLogger _log; 13 | 14 | public KeyValidator(ISplitLogger log = null) 15 | { 16 | _log = log ?? WrapperAdapter.GetLogger(typeof(KeyValidator)); 17 | } 18 | 19 | public bool IsValid(Key key, string method) 20 | { 21 | var matchingKeyIsValid = Validate(key?.matchingKey, method, nameof(key.matchingKey)); 22 | var bucketingKeyIsValid = Validate(key?.bucketingKey, method, nameof(key.bucketingKey)); 23 | 24 | return matchingKeyIsValid && bucketingKeyIsValid; 25 | } 26 | 27 | private bool Validate(string key, string method, string type) 28 | { 29 | if (key == null) 30 | { 31 | _log.Error($"{method}: you passed a null {type}, the {type} must be a non-empty string."); 32 | return false; 33 | } 34 | 35 | if (key == string.Empty) 36 | { 37 | _log.Error($"{method}: you passed an empty string, {type} must be a non-empty string."); 38 | return false; 39 | } 40 | 41 | if (key.Length > KEY_MAX_LENGTH) 42 | { 43 | _log.Error($"{method}: {type} too long - must be 250 characters or less."); 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Classes/TrafficTypeValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Interfaces; 3 | using Splitio.Services.InputValidation.Interfaces; 4 | using Splitio.Services.Logger; 5 | using Splitio.Services.Shared.Classes; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.InputValidation.Classes 9 | { 10 | public class TrafficTypeValidator : ITrafficTypeValidator 11 | { 12 | private readonly ISplitLogger _log; 13 | private readonly ISplitCache _splitCache; 14 | 15 | public TrafficTypeValidator(ISplitCache splitCache, ISplitLogger log = null) 16 | { 17 | _log = log ?? WrapperAdapter.GetLogger(typeof(TrafficTypeValidator)); 18 | _splitCache = splitCache; 19 | } 20 | 21 | public ValidatorResult IsValid(string trafficType, string method) 22 | { 23 | if (trafficType == null) 24 | { 25 | _log.Error($"{method}: you passed a null traffic_type, traffic_type must be a non-empty string"); 26 | return new ValidatorResult { Success = false }; 27 | } 28 | 29 | if (trafficType == string.Empty) 30 | { 31 | _log.Error($"{method}: you passed an empty traffic_type, traffic_type must be a non-empty string"); 32 | return new ValidatorResult { Success = false }; 33 | } 34 | 35 | if (trafficType.Any(ch => char.IsUpper(ch))) 36 | { 37 | _log.Warn($"{method}: {trafficType} should be all lowercase - converting string to lowercase"); 38 | 39 | trafficType = trafficType.ToLower(); 40 | } 41 | 42 | if (!_splitCache.TrafficTypeExists(trafficType)) 43 | { 44 | _log.Warn($"Track: Traffic Type {trafficType} does not have any corresponding Splits in this environment, make sure you’re tracking your events to a valid traffic type defined in the Split console."); 45 | } 46 | 47 | return new ValidatorResult { Success = true, Value = trafficType }; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/IApiKeyValidator.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.InputValidation.Interfaces 2 | { 3 | public interface IApiKeyValidator 4 | { 5 | void Validate(string apiKey); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/IEventPropertiesValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.InputValidation.Interfaces 5 | { 6 | public interface IEventPropertiesValidator 7 | { 8 | EventValidatorResult IsValid(Dictionary properties); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/IEventTypeValidator.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.InputValidation.Interfaces 2 | { 3 | public interface IEventTypeValidator 4 | { 5 | bool IsValid(string eventType, string method); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/IKeyValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.InputValidation.Interfaces 4 | { 5 | public interface IKeyValidator 6 | { 7 | bool IsValid(Key key, string method); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/ISplitNameValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Generic; 3 | 4 | namespace Splitio.Services.InputValidation.Interfaces 5 | { 6 | public interface ISplitNameValidator 7 | { 8 | List SplitNamesAreValid(List splitNames, string method); 9 | ValidatorResult SplitNameIsValid(string splitName, string method); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/InputValidation/Interfaces/ITrafficTypeValidator.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.InputValidation.Interfaces 4 | { 5 | public interface ITrafficTypeValidator 6 | { 7 | ValidatorResult IsValid(string trafficType, string method); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Logger/CommonLogging.cs: -------------------------------------------------------------------------------- 1 | #if NET40 || NET45 2 | using Common.Logging; 3 | using System; 4 | 5 | namespace Splitio.Services.Logger 6 | { 7 | public class CommonLogging : ISplitLogger 8 | { 9 | private ILog _logger; 10 | 11 | public CommonLogging(Type type) 12 | { 13 | _logger = LogManager.GetLogger(type); 14 | } 15 | 16 | public CommonLogging(string type) 17 | { 18 | _logger = LogManager.GetLogger(type); 19 | } 20 | 21 | public void Debug(string message, Exception exception) 22 | { 23 | _logger.Debug(message, exception); 24 | } 25 | 26 | public void Debug(string message) 27 | { 28 | _logger.Debug(message); 29 | } 30 | 31 | public void Error(string message, Exception exception) 32 | { 33 | _logger.Error(message, exception); 34 | } 35 | 36 | public void Error(string message) 37 | { 38 | _logger.Error(message); 39 | } 40 | 41 | public void Info(string message, Exception exception) 42 | { 43 | _logger.Info(message, exception); 44 | } 45 | 46 | public void Info(string message) 47 | { 48 | _logger.Info(message); 49 | } 50 | 51 | public void Trace(string message, Exception exception) 52 | { 53 | _logger.Trace(message, exception); 54 | } 55 | 56 | public void Trace(string message) 57 | { 58 | _logger.Trace(message); 59 | } 60 | 61 | public void Warn(string message, Exception exception) 62 | { 63 | _logger.Warn(message, exception); 64 | } 65 | 66 | public void Warn(string message) 67 | { 68 | _logger.Warn(message); 69 | } 70 | 71 | public bool IsDebugEnabled => _logger.IsDebugEnabled; 72 | } 73 | } 74 | #endif -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Logger/ISplitLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Splitio.Services.Logger 4 | { 5 | public interface ISplitLogger 6 | { 7 | void Debug(string message, Exception exception); 8 | void Debug(string message); 9 | void Error(string message, Exception exception); 10 | void Error(string message); 11 | void Info(string message, Exception exception); 12 | void Info(string message); 13 | void Trace(string message, Exception exception); 14 | void Trace(string message); 15 | void Warn(string message, Exception exception); 16 | void Warn(string message); 17 | 18 | bool IsDebugEnabled { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Logger/MicrosoftExtensionsLogging.cs: -------------------------------------------------------------------------------- 1 | # if NETSTANDARD 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | 5 | namespace Splitio.Services.Logger 6 | { 7 | public class MicrosoftExtensionsLogging : ISplitLogger 8 | { 9 | private const int DefaultLoggingEvent = 0; 10 | 11 | private static ILoggerFactory _loggerFactory => SplitLoggerFactoryExtensions.GetLoggerFactory() ?? new LoggerFactory(); 12 | 13 | private readonly ILogger _logger; 14 | 15 | public MicrosoftExtensionsLogging(Type type) 16 | { 17 | _logger = _loggerFactory.CreateLogger(type); 18 | } 19 | 20 | public MicrosoftExtensionsLogging(string type) 21 | { 22 | _logger = _loggerFactory.CreateLogger(type); 23 | } 24 | 25 | public void Debug(string message, Exception exception) 26 | { 27 | _logger.LogDebug(DefaultLoggingEvent, exception, message); 28 | } 29 | 30 | public void Debug(string message) 31 | { 32 | _logger.LogDebug(message); 33 | } 34 | 35 | public void Error(string message, Exception exception) 36 | { 37 | _logger.LogError(DefaultLoggingEvent, exception, message); 38 | } 39 | 40 | public void Error(string message) 41 | { 42 | _logger.LogError(message); 43 | } 44 | 45 | public void Info(string message, Exception exception) 46 | { 47 | _logger.LogInformation(DefaultLoggingEvent, exception, message); 48 | } 49 | 50 | public void Info(string message) 51 | { 52 | _logger.LogInformation(message); 53 | } 54 | 55 | public void Trace(string message, Exception exception) 56 | { 57 | _logger.LogTrace(DefaultLoggingEvent, exception, message); 58 | } 59 | 60 | public void Trace(string message) 61 | { 62 | _logger.LogTrace(message); 63 | } 64 | 65 | public void Warn(string message, Exception exception) 66 | { 67 | _logger.LogWarning(DefaultLoggingEvent, exception, message); 68 | } 69 | 70 | public void Warn(string message) 71 | { 72 | _logger.LogWarning(message); 73 | } 74 | 75 | public bool IsDebugEnabled => _logger.IsEnabled(LogLevel.Debug); 76 | } 77 | } 78 | #endif -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Logger/SplitLoggerFactoryExtensions.cs: -------------------------------------------------------------------------------- 1 | # if NETSTANDARD 2 | namespace Microsoft.Extensions.Logging 3 | { 4 | public static class SplitLoggerFactoryExtensions 5 | { 6 | private static ILoggerFactory _loggerFactory; 7 | 8 | public static ILoggerFactory AddSplitLogs(this ILoggerFactory factory) 9 | { 10 | _loggerFactory = factory; 11 | 12 | return factory; 13 | } 14 | 15 | public static ILoggerFactory GetLoggerFactory() 16 | { 17 | return _loggerFactory; 18 | } 19 | } 20 | } 21 | #endif -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Classes/BinarySearchLatencyTracker.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Metrics.Interfaces; 2 | using System; 3 | 4 | namespace Splitio.Services.Metrics.Classes 5 | { 6 | public class BinarySearchLatencyTracker : ILatencyTracker 7 | { 8 | 9 | static long[] BUCKETS = { 10 | 1000, 1500, 2250, 3375, 5063, 11 | 7594, 11391, 17086, 25629, 38443, 12 | 57665, 86498, 129746, 194620, 291929, 13 | 437894, 656841, 985261, 1477892, 2216838, 14 | 3325257, 4987885, 7481828 15 | }; 16 | 17 | static long MAX_LATENCY = 7481828; 18 | 19 | long[] latencies = new long[BUCKETS.Length]; 20 | 21 | 22 | public void AddLatencyMillis(long millis) 23 | { 24 | int index = FindIndex(millis * 1000); 25 | latencies[index]++; 26 | } 27 | 28 | 29 | public void AddLatencyMicros(long micros) 30 | { 31 | int index = FindIndex(micros); 32 | latencies[index]++; 33 | } 34 | 35 | public long[] GetLatencies() 36 | { 37 | return latencies; 38 | } 39 | 40 | public long GetLatency(int index) 41 | { 42 | return latencies[index]; 43 | } 44 | 45 | public long GetBucketForLatencyMillis(long latency) 46 | { 47 | return latencies[FindIndex(latency * 1000)]; 48 | } 49 | 50 | public long GetBucketForLatencyMicros(long latency) 51 | { 52 | return latencies[FindIndex(latency)]; 53 | } 54 | 55 | public int FindIndex(long micros) 56 | { 57 | if (micros > MAX_LATENCY) 58 | { 59 | return BUCKETS.Length - 1; 60 | } 61 | 62 | int index = Array.BinarySearch(BUCKETS, micros); 63 | 64 | if (index < 0) 65 | { 66 | //When index is negative, do bitwise negation 67 | index = ~index; 68 | } 69 | return index; 70 | } 71 | 72 | public void SetLatencyCount(int index, long count) 73 | { 74 | latencies[index] = count; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Classes/Counter.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Metrics.Classes 2 | { 3 | public class Counter 4 | { 5 | private int count = 0; 6 | private long sum = 0; 7 | 8 | public Counter():base() 9 | { } 10 | 11 | public Counter(long delta) 12 | { 13 | count++; 14 | sum = delta; 15 | } 16 | 17 | public int GetCount() 18 | { 19 | return count; 20 | } 21 | 22 | public long GetDelta() 23 | { 24 | return sum; 25 | } 26 | 27 | public void AddDelta(long delta) 28 | { 29 | count++; 30 | sum += delta; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Classes/MetricsSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Metrics.Interfaces; 4 | using Splitio.Services.Shared.Classes; 5 | using System.Net; 6 | 7 | namespace Splitio.Services.Metrics.Classes 8 | { 9 | public class MetricsSdkApiClient : SdkApiClient, IMetricsSdkApiClient 10 | { 11 | private const string MetricsUrlTemplate = "/api/metrics/{endpoint}"; 12 | 13 | private static readonly ISplitLogger Log = WrapperAdapter.GetLogger(typeof(MetricsSdkApiClient)); 14 | 15 | public MetricsSdkApiClient(HTTPHeader header, string baseUrl, long connectionTimeOut, long readTimeout) 16 | : base(header, baseUrl, connectionTimeOut, readTimeout) 17 | { } 18 | 19 | public async void SendCountMetrics(string metrics) 20 | { 21 | var response = await ExecutePost(MetricsUrlTemplate.Replace("{endpoint}", "counters"), metrics); 22 | 23 | if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous) 24 | { 25 | Log.Error(string.Format("Http status executing SendCountMetrics: {0} - {1}", response.statusCode.ToString(), response.content)); 26 | } 27 | } 28 | 29 | public async void SendTimeMetrics(string metrics) 30 | { 31 | var response = await ExecutePost(MetricsUrlTemplate.Replace("{endpoint}", "times"), metrics); 32 | 33 | if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous) 34 | { 35 | Log.Error(string.Format("Http status executing SendTimeMetrics: {0} - {1}", response.statusCode.ToString(), response.content)); 36 | } 37 | } 38 | 39 | public async void SendGaugeMetrics(string metrics) 40 | { 41 | var response = await ExecutePost(MetricsUrlTemplate.Replace("{endpoint}", "gauge"), metrics); 42 | 43 | if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous) 44 | { 45 | Log.Error(string.Format("Http status executing SendGaugeMetrics: {0} - {1}", response.statusCode.ToString(), response.content)); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Interfaces/ILatencyTracker.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Metrics.Interfaces 2 | { 3 | public interface ILatencyTracker 4 | { 5 | 6 | void AddLatencyMillis(long millis); 7 | 8 | void AddLatencyMicros(long micros); 9 | 10 | long[] GetLatencies(); 11 | 12 | long GetLatency(int index); 13 | 14 | long GetBucketForLatencyMillis(long latency); 15 | 16 | long GetBucketForLatencyMicros(long latency); 17 | 18 | void SetLatencyCount(int index, long count); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Interfaces/IMetricsLog.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Metrics.Interfaces 2 | { 3 | public interface IMetricsLog 4 | { 5 | void Start(); 6 | void Count(string counterName, long delta); 7 | void Time(string operation, long miliseconds); 8 | void Gauge(string gauge, long value); 9 | void Clear(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Metrics/Interfaces/IMetricsSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Metrics.Interfaces 2 | { 3 | public interface IMetricsSdkApiClient 4 | { 5 | void SendCountMetrics(string metrics); 6 | 7 | void SendTimeMetrics(string metrics); 8 | 9 | void SendGaugeMetrics(string metrics); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/AllKeysMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class AllKeysMatcher : BaseMatcher 10 | { 11 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 12 | { 13 | return key != null; 14 | } 15 | 16 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 17 | { 18 | return key != null; 19 | } 20 | 21 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 22 | { 23 | return true; 24 | } 25 | 26 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 27 | { 28 | return false; 29 | } 30 | 31 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 32 | { 33 | return key.matchingKey != null; 34 | } 35 | 36 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 37 | { 38 | return false; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/BaseMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Services.Parsing.Classes 7 | { 8 | public abstract class BaseMatcher : IMatcher 9 | { 10 | public abstract bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null); 11 | 12 | public abstract bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null); 13 | 14 | public abstract bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null); 15 | 16 | public abstract bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null); 17 | 18 | public abstract bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null); 19 | 20 | public abstract bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null); 21 | 22 | public bool Match(object value, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (value is bool) 25 | { 26 | return Match((bool)value, attributes, evaluator); 27 | } 28 | else if (value is string) 29 | { 30 | return Match((string)value, attributes, evaluator); 31 | } 32 | else if (value is DateTime) 33 | { 34 | return Match((DateTime)value, attributes, evaluator); 35 | } 36 | else if (value is long) 37 | { 38 | return Match((long)value, attributes, evaluator); 39 | } 40 | else if (value is int) 41 | { 42 | return Match((int)value, attributes, evaluator); 43 | } 44 | else if (value is List) 45 | { 46 | return Match((List)value, attributes, evaluator); 47 | } 48 | else if (value is Key) 49 | { 50 | return Match((Key)value, attributes, evaluator); 51 | } 52 | 53 | return false; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/BetweenMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Domain; 3 | using Splitio.Services.Evaluator; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class BetweenMatcher : CompareMatcher 10 | { 11 | 12 | public BetweenMatcher(DataTypeEnum? dataType, long start, long end) 13 | { 14 | this.dataType = dataType; 15 | this.start = start; 16 | this.end = end; 17 | } 18 | 19 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 20 | { 21 | return (start <= key) && (key <= end); 22 | } 23 | 24 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 25 | { 26 | var startDate = start.ToDateTime(); 27 | var endDate = end.ToDateTime(); 28 | key = key.Truncate(TimeSpan.FromMinutes(1)); // Truncate to whole minute 29 | return (startDate.ToUniversalTime() <= key.ToUniversalTime()) && (key.ToUniversalTime() <= endDate.ToUniversalTime()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/CompareMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Domain; 3 | using Splitio.Services.Evaluator; 4 | using Splitio.Services.Parsing.Classes; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public abstract class CompareMatcher : BaseMatcher 11 | { 12 | protected DataTypeEnum? dataType; 13 | protected long value; 14 | protected long start; 15 | protected long end; 16 | 17 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | switch (dataType) 20 | { 21 | case DataTypeEnum.DATETIME: 22 | var date = key.ToDateTime(); 23 | return date != null ? Match(date.Value) : false; 24 | case DataTypeEnum.NUMBER: 25 | long number; 26 | var result = long.TryParse(key, out number); 27 | return result ? Match(number) : false; 28 | default: return false; 29 | } 30 | } 31 | 32 | public abstract override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null); 33 | 34 | public abstract override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null); 35 | 36 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 37 | { 38 | return false; 39 | } 40 | 41 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 42 | { 43 | return Match(key.matchingKey, attributes, evaluator); 44 | } 45 | 46 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 47 | { 48 | return false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/ContainsAllOfSetMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class ContainsAllOfSetMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public ContainsAllOfSetMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (key == null || itemsToCompare.Count == 0) 25 | { 26 | return false; 27 | } 28 | 29 | return itemsToCompare.All(i => key.Contains(i)); 30 | } 31 | 32 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return false; 35 | } 36 | 37 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/ContainsAnyOfSetMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class ContainsAnyOfSetMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public ContainsAnyOfSetMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (key == null || itemsToCompare.Count == 0) 25 | { 26 | return false; 27 | } 28 | 29 | return itemsToCompare.Any(i => key.Contains(i)); 30 | } 31 | 32 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return false; 35 | } 36 | 37 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/ContainsStringMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class ContainsStringMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public ContainsStringMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (string.IsNullOrEmpty(key)) 25 | { 26 | return false; 27 | } 28 | 29 | return itemsToCompare.Any(i => key.Contains(i)); 30 | } 31 | 32 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return Match(key.matchingKey, attributes, evaluator); 35 | } 36 | 37 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/DependencyMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Services.Parsing.Classes 7 | { 8 | public class DependencyMatcher : BaseMatcher 9 | { 10 | private readonly string Split; 11 | private readonly List Treatments; 12 | 13 | public DependencyMatcher(string split, List treatments) 14 | { 15 | Split = split; 16 | Treatments = treatments; 17 | } 18 | 19 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 20 | { 21 | if (evaluator == null) 22 | { 23 | return false; 24 | } 25 | 26 | var result = evaluator.EvaluateFeature(key, Split, attributes); 27 | 28 | return Treatments.Contains(result.Treatment); 29 | } 30 | 31 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 32 | { 33 | return false; 34 | } 35 | 36 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 37 | { 38 | return false; 39 | 40 | } 41 | 42 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/EndsWithMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class EndsWithMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public EndsWithMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (string.IsNullOrEmpty(key)) 25 | { 26 | return false; 27 | } 28 | 29 | return itemsToCompare.Any(i => key.EndsWith(i)); 30 | } 31 | 32 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return Match(key.matchingKey, attributes, evaluator); 35 | } 36 | 37 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/EqualToBooleanMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Services.Parsing.Classes 7 | { 8 | public class EqualToBooleanMatcher : BaseMatcher 9 | { 10 | private readonly bool Value; 11 | 12 | public EqualToBooleanMatcher(bool value) 13 | { 14 | Value = value; 15 | } 16 | 17 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | return key.Equals(Value); 20 | } 21 | 22 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (bool.TryParse(key, out bool boolValue)) 25 | { 26 | return Match(boolValue, attributes, evaluator); 27 | } 28 | else 29 | { 30 | return false; 31 | } 32 | } 33 | 34 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 35 | { 36 | return false; 37 | } 38 | 39 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 40 | { 41 | return false; 42 | } 43 | 44 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 45 | { 46 | return false; 47 | } 48 | 49 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 50 | { 51 | return false; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/EqualToMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Domain; 3 | using Splitio.Services.Evaluator; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class EqualToMatcher : CompareMatcher 10 | { 11 | public EqualToMatcher(DataTypeEnum? dataType, long value) 12 | { 13 | this.dataType = dataType; 14 | this.value = value; 15 | } 16 | 17 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | if (dataType == DataTypeEnum.DATETIME) 20 | { 21 | return Match(key.ToDateTime(), attributes, evaluator); 22 | } 23 | 24 | return value == key; 25 | } 26 | 27 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 28 | { 29 | var date = value.ToDateTime(); 30 | 31 | return date.ToUniversalTime().Date == key.ToUniversalTime().Date; // Compare just date part 32 | } 33 | 34 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 35 | { 36 | return false; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/EqualToSetMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class EqualToSetMatcher : BaseMatcher 10 | { 11 | private HashSet itemsToCompare = new HashSet(); 12 | 13 | public EqualToSetMatcher(List compareTo) 14 | { 15 | if (compareTo != null) 16 | { 17 | itemsToCompare.UnionWith(compareTo); 18 | } 19 | } 20 | 21 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 22 | { 23 | return false; 24 | } 25 | 26 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 27 | { 28 | if (key == null) 29 | { 30 | return false; 31 | } 32 | 33 | return itemsToCompare.SetEquals(key); 34 | } 35 | 36 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 37 | { 38 | return false; 39 | } 40 | 41 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 42 | { 43 | return false; 44 | } 45 | 46 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 47 | { 48 | return false; 49 | } 50 | 51 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 52 | { 53 | return false; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/GreaterOrEqualToMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Domain; 3 | using Splitio.Services.Evaluator; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class GreaterOrEqualToMatcher : CompareMatcher 10 | { 11 | public GreaterOrEqualToMatcher(DataTypeEnum? dataType, long value) 12 | { 13 | this.dataType = dataType; 14 | this.value = value; 15 | } 16 | 17 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | return key >= value; 20 | } 21 | 22 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | var date = value.ToDateTime(); 25 | key = key.Truncate(TimeSpan.FromMinutes(1)); // Truncate to whole minute 26 | return key.ToUniversalTime() >= date.ToUniversalTime(); 27 | } 28 | 29 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 30 | { 31 | return false; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/InMemorySplitParser.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Interfaces; 3 | using Splitio.Services.SegmentFetcher.Interfaces; 4 | 5 | namespace Splitio.Services.Parsing.Classes 6 | { 7 | public class InMemorySplitParser : SplitParser 8 | { 9 | private readonly ISegmentFetcher _segmentFetcher; 10 | 11 | public InMemorySplitParser(ISegmentFetcher segmentFetcher, ISegmentCache segmentsCache) 12 | { 13 | _segmentFetcher = segmentFetcher; 14 | _segmentsCache = segmentsCache; 15 | } 16 | 17 | protected override IMatcher GetInSegmentMatcher(MatcherDefinition matcherDefinition, ParsedSplit parsedSplit) 18 | { 19 | var matcherData = matcherDefinition.userDefinedSegmentMatcherData; 20 | _segmentFetcher.InitializeSegment(matcherData.segmentName); 21 | 22 | return new UserDefinedSegmentMatcher(matcherData.segmentName, _segmentsCache); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/LessOrEqualToMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.CommonLibraries; 2 | using Splitio.Domain; 3 | using Splitio.Services.Evaluator; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class LessOrEqualToMatcher : CompareMatcher 10 | { 11 | public LessOrEqualToMatcher(DataTypeEnum? dataType, long value) 12 | { 13 | this.dataType = dataType; 14 | this.value = value; 15 | } 16 | 17 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | return key <= value; 20 | } 21 | 22 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | var date = value.ToDateTime(); 25 | key = key.Truncate(TimeSpan.FromMinutes(1)); // Truncate to whole minute 26 | return key.ToUniversalTime() <= date.ToUniversalTime(); 27 | } 28 | 29 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 30 | { 31 | return false; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/MatchesStringMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace Splitio.Services.Parsing.Classes 8 | { 9 | public class MatchesStringMatcher : BaseMatcher 10 | { 11 | Regex regex; 12 | 13 | public MatchesStringMatcher(string pattern) 14 | { 15 | regex = new Regex(pattern); 16 | } 17 | 18 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 19 | { 20 | return regex.IsMatch(key); 21 | } 22 | 23 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 24 | { 25 | return regex.IsMatch(key.matchingKey); 26 | } 27 | 28 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 29 | { 30 | return false; 31 | } 32 | 33 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 34 | { 35 | return false; 36 | } 37 | 38 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 39 | { 40 | return false; 41 | } 42 | 43 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 44 | { 45 | return false; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/PartOfSetMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class PartOfSetMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public PartOfSetMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (key == null || key.Count == 0) 25 | { 26 | return false; 27 | } 28 | 29 | return key.All(k => itemsToCompare.Contains(k)); 30 | } 31 | 32 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return false; 35 | } 36 | 37 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/StartsWithMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class StartsWithMatcher : BaseMatcher 11 | { 12 | private HashSet itemsToCompare = new HashSet(); 13 | 14 | public StartsWithMatcher(List compareTo) 15 | { 16 | if (compareTo != null) 17 | { 18 | itemsToCompare.UnionWith(compareTo); 19 | } 20 | } 21 | 22 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | if (string.IsNullOrEmpty(key)) 25 | { 26 | return false; 27 | } 28 | 29 | return itemsToCompare.Any(i => key.StartsWith(i)); 30 | } 31 | 32 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return Match(key.matchingKey, attributes, evaluator); 35 | } 36 | 37 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | 47 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 48 | { 49 | return false; 50 | } 51 | 52 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 53 | { 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/UserDefinedSegmentMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Interfaces; 3 | using Splitio.Services.Evaluator; 4 | using Splitio.Services.Parsing.Classes; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Splitio.Services.Parsing 9 | { 10 | public class UserDefinedSegmentMatcher : BaseMatcher 11 | { 12 | private string segmentName; 13 | private ISegmentCache segmentsCache; 14 | 15 | public UserDefinedSegmentMatcher(string segmentName, ISegmentCache segmentsCache) 16 | { 17 | this.segmentName = segmentName; 18 | this.segmentsCache = segmentsCache; 19 | } 20 | 21 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 22 | { 23 | return segmentsCache.IsInSegment(segmentName, key); 24 | } 25 | 26 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 27 | { 28 | return Match(key.matchingKey, attributes, evaluator); 29 | } 30 | 31 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 32 | { 33 | return false; 34 | } 35 | 36 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 37 | { 38 | return false; 39 | } 40 | 41 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 42 | { 43 | return false; 44 | } 45 | 46 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 47 | { 48 | return false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Classes/WhitelistMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using Splitio.Services.Parsing.Classes; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Splitio.Services.Parsing 8 | { 9 | public class WhitelistMatcher: BaseMatcher 10 | { 11 | private List list; 12 | 13 | public WhitelistMatcher(List list) 14 | { 15 | this.list = list ?? new List(); 16 | } 17 | public override bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null) 18 | { 19 | return list.Contains(key); 20 | } 21 | 22 | public override bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null) 23 | { 24 | return Match(key.matchingKey, attributes, evaluator); 25 | } 26 | 27 | public override bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null) 28 | { 29 | return false; 30 | } 31 | 32 | public override bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null) 33 | { 34 | return false; 35 | } 36 | 37 | public override bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null) 38 | { 39 | return false; 40 | } 41 | 42 | public override bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null) 43 | { 44 | return false; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Interfaces/IMatcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Evaluator; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Splitio.Services.Parsing 7 | { 8 | public interface IMatcher 9 | { 10 | bool Match(object value, Dictionary attributes = null, IEvaluator evaluator = null); 11 | 12 | bool Match(string key, Dictionary attributes = null, IEvaluator evaluator = null); 13 | 14 | bool Match(Key key, Dictionary attributes = null, IEvaluator evaluator = null); 15 | 16 | bool Match(DateTime key, Dictionary attributes = null, IEvaluator evaluator = null); 17 | 18 | bool Match(long key, Dictionary attributes = null, IEvaluator evaluator = null); 19 | 20 | bool Match(List key, Dictionary attributes = null, IEvaluator evaluator = null); 21 | 22 | bool Match(bool key, Dictionary attributes = null, IEvaluator evaluator = null); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Parsing/Interfaces/ISplitParser.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | 3 | namespace Splitio.Services.Parsing.Interfaces 4 | { 5 | public interface ISplitParser 6 | { 7 | ParsedSplit Parse(Split split); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Classes/ApiSegmentChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.Domain; 3 | using Splitio.Services.SegmentFetcher.Interfaces; 4 | using Splitio.Services.SplitFetcher.Interfaces; 5 | using System.Threading.Tasks; 6 | 7 | namespace Splitio.Services.SegmentFetcher.Classes 8 | { 9 | public class ApiSegmentChangeFetcher: SegmentChangeFetcher, ISegmentChangeFetcher 10 | { 11 | private readonly ISegmentSdkApiClient apiClient; 12 | 13 | public ApiSegmentChangeFetcher(ISegmentSdkApiClient apiClient) 14 | { 15 | this.apiClient = apiClient; 16 | } 17 | 18 | protected override async Task FetchFromBackend(string name, long since) 19 | { 20 | var fetchResult = await apiClient.FetchSegmentChanges(name, since); 21 | 22 | var segmentChange = JsonConvert.DeserializeObject(fetchResult); 23 | return segmentChange; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Classes/JSONFileSegmentFetcher.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.Domain; 3 | using Splitio.Services.Cache.Interfaces; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | 7 | namespace Splitio.Services.SegmentFetcher.Classes 8 | { 9 | public class JSONFileSegmentFetcher : SegmentFetcher 10 | { 11 | List added; 12 | 13 | public JSONFileSegmentFetcher(string filePath, 14 | ISegmentCache segmentsCache) : base(segmentsCache) 15 | { 16 | if (!string.IsNullOrEmpty(filePath)) 17 | { 18 | var json = File.ReadAllText(filePath); 19 | var segmentChangesResult = JsonConvert.DeserializeObject(json); 20 | added = segmentChangesResult.added; 21 | } 22 | } 23 | 24 | public override void InitializeSegment(string name) 25 | { 26 | if (added != null) 27 | { 28 | _segmentCache.AddToSegment(name, added); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Classes/SegmentChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.SegmentFetcher.Interfaces; 4 | using Splitio.Services.Shared.Classes; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace Splitio.Services.SegmentFetcher.Classes 9 | { 10 | public abstract class SegmentChangeFetcher: ISegmentChangeFetcher 11 | { 12 | private SegmentChange segmentChange; 13 | private static readonly ISplitLogger Log = WrapperAdapter.GetLogger(typeof(SegmentChangeFetcher)); 14 | 15 | protected abstract Task FetchFromBackend(string name, long since); 16 | 17 | public async Task Fetch(string name, long since) 18 | { 19 | try 20 | { 21 | segmentChange = await FetchFromBackend(name, since); 22 | } 23 | catch(Exception e) 24 | { 25 | Log.Error(string.Format("Exception caught executing fetch segment changes since={0}", since), e); 26 | segmentChange = null; 27 | } 28 | return segmentChange; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Classes/SegmentFetcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Cache.Classes; 3 | using Splitio.Services.Cache.Interfaces; 4 | using Splitio.Services.SegmentFetcher.Interfaces; 5 | using System.Collections.Concurrent; 6 | 7 | namespace Splitio.Services.SegmentFetcher.Classes 8 | { 9 | public class SegmentFetcher : ISegmentFetcher 10 | { 11 | protected ISegmentCache _segmentCache; 12 | 13 | public SegmentFetcher(ISegmentCache segmentCache) 14 | { 15 | _segmentCache = segmentCache ?? new InMemorySegmentCache(new ConcurrentDictionary()); 16 | } 17 | 18 | public virtual void InitializeSegment(string name) { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Classes/SegmentTaskQueue.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.SegmentFetcher.Interfaces; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Splitio.Services.SegmentFetcher.Classes 5 | { 6 | public class SegmentTaskQueue : ISegmentTaskQueue 7 | { 8 | private readonly BlockingCollection _segmentsQueue; 9 | 10 | public SegmentTaskQueue() 11 | { 12 | _segmentsQueue = new BlockingCollection(new ConcurrentQueue()); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | _segmentsQueue.Dispose(); 18 | } 19 | 20 | public void Add(SelfRefreshingSegment selfRefreshingSegment) 21 | { 22 | _segmentsQueue.TryAdd(selfRefreshingSegment); 23 | } 24 | 25 | public BlockingCollection GetQueue() 26 | { 27 | return _segmentsQueue; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISegment.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.SegmentFetcher.Interfaces 2 | { 3 | public interface ISegment 4 | { 5 | bool Contains(string key); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISegmentChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Threading.Tasks; 3 | 4 | namespace Splitio.Services.SegmentFetcher.Interfaces 5 | { 6 | public interface ISegmentChangeFetcher 7 | { 8 | Task Fetch(string name, long change_number); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISegmentFetcher.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.SegmentFetcher.Interfaces 2 | { 3 | public interface ISegmentFetcher 4 | { 5 | void InitializeSegment(string name); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISegmentSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.SplitFetcher.Interfaces 4 | { 5 | public interface ISegmentSdkApiClient 6 | { 7 | Task FetchSegmentChanges(string name, long since); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISegmentTaskQueue.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.SegmentFetcher.Classes; 2 | using System; 3 | using System.Collections.Concurrent; 4 | 5 | namespace Splitio.Services.SegmentFetcher.Interfaces 6 | { 7 | public interface ISegmentTaskQueue : IDisposable 8 | { 9 | void Add(SelfRefreshingSegment selfRefreshingSegment); 10 | BlockingCollection GetQueue(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISelfRefreshingSegment.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.SegmentFetcher.Interfaces 4 | { 5 | public interface ISelfRefreshingSegment 6 | { 7 | Task FetchSegment(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SegmentFetcher/Interfaces/ISelfRefreshingSegmentFetcher.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.SegmentFetcher.Interfaces 4 | { 5 | public interface ISelfRefreshingSegmentFetcher 6 | { 7 | void Start(); 8 | void Stop(); 9 | Task FetchAll(); 10 | Task Fetch(string segmentName); 11 | void Clear(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Classes/BlockingQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace Splitio.Services.Shared.Classes 4 | { 5 | public class BlockingQueue 6 | { 7 | private ConcurrentQueue queue = new ConcurrentQueue(); 8 | private object lockingObject = new object(); 9 | 10 | private readonly int maxSize; 11 | 12 | public BlockingQueue(int maxSize) 13 | { 14 | this.maxSize = maxSize; 15 | } 16 | 17 | public bool HasReachedMaxSize() 18 | { 19 | return queue.Count >= maxSize; 20 | } 21 | 22 | public ConcurrentQueue FetchAll() 23 | { 24 | lock (lockingObject) 25 | { 26 | var existingItems = new ConcurrentQueue(queue); 27 | return existingItems; 28 | } 29 | } 30 | 31 | public ConcurrentQueue FetchAllAndClear() 32 | { 33 | lock (lockingObject) 34 | { 35 | var existingItems = new ConcurrentQueue(queue); 36 | queue = new ConcurrentQueue(); 37 | return existingItems; 38 | } 39 | } 40 | 41 | public void Enqueue(T item) 42 | { 43 | lock (lockingObject) 44 | { 45 | if (!HasReachedMaxSize()) 46 | { 47 | queue.Enqueue(item); 48 | } 49 | } 50 | } 51 | public T Dequeue() 52 | { 53 | lock (lockingObject) 54 | { 55 | T item; 56 | queue.TryDequeue(out item); 57 | return item; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Classes/InMemorySimpleCache.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Shared.Interfaces; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Splitio.Services.Shared.Classes 6 | { 7 | public class InMemorySimpleCache : ISimpleProducerCache 8 | { 9 | private readonly BlockingQueue _queue; 10 | 11 | public InMemorySimpleCache(BlockingQueue queue) 12 | { 13 | _queue = queue; 14 | } 15 | 16 | public void AddItems(IList items) 17 | { 18 | if (_queue != null) 19 | { 20 | foreach (var item in items) 21 | { 22 | _queue.Enqueue(item); 23 | } 24 | } 25 | } 26 | 27 | public List FetchAllAndClear() 28 | { 29 | return _queue != null ? _queue.FetchAllAndClear().ToList() : null; 30 | } 31 | 32 | public bool HasReachedMaxSize() 33 | { 34 | return _queue != null ? _queue.HasReachedMaxSize() : false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Classes/LocalhostFileService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Logger; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace Splitio.Services.Shared.Classes 9 | { 10 | public class LocalhostFileService : AbstractLocalhostFileService 11 | { 12 | public LocalhostFileService(ISplitLogger log = null) 13 | { 14 | _log = log ?? WrapperAdapter.GetLogger(typeof(LocalhostFileService)); 15 | } 16 | 17 | public override ConcurrentDictionary ParseSplitFile(string filePath) 18 | { 19 | var splits = new ConcurrentDictionary(); 20 | 21 | string line; 22 | 23 | using (var file = new StreamReader(File.OpenText(filePath).BaseStream)) 24 | { 25 | while ((line = file.ReadLine()) != null) 26 | { 27 | line = line.Trim(); 28 | if (string.IsNullOrEmpty(line) || line.StartsWith("#")) 29 | { 30 | continue; 31 | } 32 | 33 | var feature_treatment = Regex.Split(line, @"\s+"); 34 | 35 | if (feature_treatment.Length != 2) 36 | { 37 | _log.Info("Ignoring line since it does not have exactly two columns: " + line); 38 | continue; 39 | } 40 | 41 | var splitName = feature_treatment[0]; 42 | var treatment = feature_treatment[1]; 43 | var conditions = new List 44 | { 45 | CreateCondition(treatment) 46 | }; 47 | 48 | splits.TryAdd(splitName, CreateParsedSplit(splitName, treatment, conditions)); 49 | _log.Info("100% of keys will see " + treatment + " for " + splitName); 50 | 51 | } 52 | } 53 | 54 | return splits; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Classes/NoopBlockUntilReadyService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Shared.Interfaces; 2 | 3 | namespace Splitio.Services.Shared.Classes 4 | { 5 | public class NoopBlockUntilReadyService : IBlockUntilReadyService 6 | { 7 | public void BlockUntilReady(int blockMilisecondsUntilReady) { } 8 | 9 | public bool IsSdkReady() 10 | { 11 | return true; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Services.Cache.Interfaces; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Shared.Interfaces; 4 | using System; 5 | 6 | namespace Splitio.Services.Shared.Classes 7 | { 8 | public class SelfRefreshingBlockUntilReadyService : IBlockUntilReadyService 9 | { 10 | private readonly IReadinessGatesCache _gates; 11 | private readonly ISplitLogger _log; 12 | 13 | public SelfRefreshingBlockUntilReadyService(IReadinessGatesCache gates, 14 | ISplitLogger log = null) 15 | { 16 | _gates = gates; 17 | _log = log ?? WrapperAdapter.GetLogger(typeof(SelfRefreshingBlockUntilReadyService)); 18 | } 19 | 20 | public void BlockUntilReady(int blockMilisecondsUntilReady) 21 | { 22 | if (!IsSdkReady()) 23 | { 24 | if (blockMilisecondsUntilReady <= 0) 25 | { 26 | _log.Warn("The blockMilisecondsUntilReady param has to be higher than 0."); 27 | } 28 | 29 | if (!_gates.IsSDKReady(blockMilisecondsUntilReady)) 30 | { 31 | throw new TimeoutException(string.Format($"SDK was not ready in {blockMilisecondsUntilReady} miliseconds")); 32 | } 33 | } 34 | } 35 | 36 | public bool IsSdkReady() 37 | { 38 | return _gates.IsSDKReady(0); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/IBlockUntilReadyService.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Shared.Interfaces 2 | { 3 | public interface IBlockUntilReadyService 4 | { 5 | void BlockUntilReady(int blockMilisecondsUntilReady); 6 | bool IsSdkReady(); 7 | } 8 | } -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/IConfigService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Client.Classes; 3 | using Splitio.Services.Shared.Classes; 4 | 5 | namespace Splitio.Services.Shared.Interfaces 6 | { 7 | public interface IConfigService 8 | { 9 | BaseConfig ReadConfig(ConfigurationOptions config, ConfingTypes confingType); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/IFactoryInstantiationsService.cs: -------------------------------------------------------------------------------- 1 | namespace Splitio.Services.Shared.Interfaces 2 | { 3 | public interface IFactoryInstantiationsService 4 | { 5 | void Decrease(string apiKey); 6 | void Increase(string apiKey); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/ILocalhostFileService.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Splitio.Services.Shared.Interfaces 5 | { 6 | public interface ILocalhostFileService 7 | { 8 | ConcurrentDictionary ParseSplitFile(string filePath); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/ISimpleCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Services.Shared.Interfaces 4 | { 5 | public interface ISimpleCache 6 | { 7 | void AddItems(IList items); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/ISimpleProducerCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Splitio.Services.Shared.Interfaces 4 | { 5 | public interface ISimpleProducerCache : ISimpleCache 6 | { 7 | List FetchAllAndClear(); 8 | bool HasReachedMaxSize(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/Shared/Interfaces/IWrapperAdapter.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Client.Classes; 3 | using Splitio.Services.Logger; 4 | using System.Threading.Tasks; 5 | 6 | namespace Splitio.Services.Shared.Interfaces 7 | { 8 | public interface IWrapperAdapter 9 | { 10 | ReadConfigData ReadConfig(ConfigurationOptions config, ISplitLogger log); 11 | Task TaskDelay(int millisecondsDelay); 12 | Task WhenAny(params Task[] tasks); 13 | Task TaskFromResult(T result); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Classes/ApiSplitChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.Domain; 3 | using Splitio.Services.SplitFetcher.Interfaces; 4 | using System.Threading.Tasks; 5 | 6 | namespace Splitio.Services.SplitFetcher.Classes 7 | { 8 | public class ApiSplitChangeFetcher: SplitChangeFetcher, ISplitChangeFetcher 9 | { 10 | private readonly ISplitSdkApiClient apiClient; 11 | 12 | public ApiSplitChangeFetcher(ISplitSdkApiClient apiClient) 13 | { 14 | this.apiClient = apiClient; 15 | } 16 | 17 | protected override async Task FetchFromBackend(long since) 18 | { 19 | var fetchResult = await apiClient.FetchSplitChanges(since); 20 | 21 | var splitChangesResult = JsonConvert.DeserializeObject(fetchResult); 22 | return splitChangesResult; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Classes/JSONFileSplitChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Splitio.Domain; 3 | using Splitio.Services.Cache.Interfaces; 4 | using Splitio.Services.Shared.Classes; 5 | using Splitio.Services.Shared.Interfaces; 6 | using Splitio.Services.SplitFetcher.Interfaces; 7 | using System.IO; 8 | using System.Threading.Tasks; 9 | 10 | namespace Splitio.Services.SplitFetcher.Classes 11 | { 12 | public class JSONFileSplitChangeFetcher : SplitChangeFetcher, ISplitChangeFetcher 13 | { 14 | private readonly IWrapperAdapter _wrapperAdapter; 15 | 16 | public ISplitCache splitCache { get; private set; } 17 | private string filePath; 18 | 19 | public JSONFileSplitChangeFetcher(string filePath) 20 | { 21 | this.filePath = filePath; 22 | 23 | _wrapperAdapter = new WrapperAdapter(); 24 | } 25 | 26 | protected override async Task FetchFromBackend(long since) 27 | { 28 | var json = File.ReadAllText(filePath); 29 | var splitChangesResult = JsonConvert.DeserializeObject(json); 30 | 31 | return await _wrapperAdapter.TaskFromResult(splitChangesResult); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Classes/SplitChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using Splitio.Services.Logger; 3 | using Splitio.Services.Shared.Classes; 4 | using Splitio.Services.SplitFetcher.Interfaces; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace Splitio.Services.SplitFetcher.Classes 9 | { 10 | public abstract class SplitChangeFetcher : ISplitChangeFetcher 11 | { 12 | private SplitChangesResult splitChanges; 13 | private static readonly ISplitLogger Log = WrapperAdapter.GetLogger(typeof(SplitChangeFetcher)); 14 | 15 | protected abstract Task FetchFromBackend(long since); 16 | 17 | public async Task Fetch(long since) 18 | { 19 | try 20 | { 21 | splitChanges = await FetchFromBackend(since); 22 | } 23 | catch(Exception e) 24 | { 25 | Log.Error(string.Format("Exception caught executing Fetch since={0}", since), e); 26 | splitChanges = null; 27 | } 28 | 29 | return splitChanges; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Interfaces/ISplitChangeFetcher.cs: -------------------------------------------------------------------------------- 1 | using Splitio.Domain; 2 | using System.Threading.Tasks; 3 | 4 | namespace Splitio.Services.SplitFetcher.Interfaces 5 | { 6 | public interface ISplitChangeFetcher 7 | { 8 | Task Fetch(long since); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Interfaces/ISplitFetcher.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.SplitFetcher.Interfaces 4 | { 5 | public interface ISplitFetcher 6 | { 7 | void Start(); 8 | void Stop(); 9 | Task FetchSplits(); 10 | void Clear(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Services/SplitFetcher/Interfaces/ISplitSdkApiClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Splitio.Services.SplitFetcher.Interfaces 4 | { 5 | public interface ISplitSdkApiClient 6 | { 7 | Task FetchSplitChanges(long since); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Splitio.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /src/Splitio-net-core/Splitio.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitio/.net-core-client/619ef84a06f44914d6d03a673ffdeab0d36039b8/src/Splitio-net-core/Splitio.snk --------------------------------------------------------------------------------