Compare commits

..

172 Commits

Author SHA1 Message Date
817f6eeaa0 Release 0.8.0-rc.1 () 2019-11-01 13:59:35 -07:00
33189f9154 Added jaeger tracing to Open Match core services () 2019-11-01 13:02:46 -07:00
9ef7cb6277 Matchmaker tutorial modificationt to improve tutorial experience () 2019-11-01 12:49:12 -07:00
b05c9f5574 Proposal: Make extension a map of string to any ()
Replaces the extension field (and match.evaluator_input) with a map of string to any.  The previous concept was that different components would read from specific extension fields.   However nothing was enforcing this behavior.  (fun fact: the very first use of this was incorrect, I used extension instead of evaluator_input when updating the default evaluator, but caught myself in the review.)

Instead have a map of string to proto.  This allows any producer to add whatever values
it wants, and the consumers to look for the specific values they want.

# Pros:
Better compos-ability, and less "forced" duplication.  Now various components can simply add information which is required by the other components processing each message.  If there is a unified system, they can use one extension.  If it's a system composed of various parts, then they simply add and use the protos required by the connected pieces.

This allows data to flow through OM better: if there are systems which are composed together outside of OM core, they don't need custom fields or manipulation. eg, if I pass my match to a well known system with returns assignments from Agones, and requires a specific extension, and I add a layer of processing before hand which requires its own extension, the match doesn't need to be modified to have the required extension when being passed to the Agones allocator.  Or if there's data on tickets which need to flow through OM to the director, they can just be added.

# Cons:
- Very simple use cases for OM are a bit more complex.
- JSON specifically now needs to add a map around the any around the actual data.
- Users who have a single extension type have a bit more work to do.  I think the recommendation should be to use the empty string, "", for such cases.
- Read, Modify, Set operations on extension data are more complicated.
2019-10-31 16:58:22 -07:00
8a29f15fe0 Unify helm image tags () 2019-10-31 16:37:09 -07:00
5fa0cc700c Refactor evaluator client in the synchronizer ()
This fixes a number of bugs:
- If it's a grpc connection, the evaluator client also creates an http connection.
- Even if it's an http connection, it never sets it to use that http connection, always trying to recreate the client and failing.
- The http evaluator code does not use the http client which it created.
- If the config is updated, the old evaluator connection details are still used.
- If the client errors, it may still use a broken client.

Refactors the file into several completely separate components:
- A grpc based client.
- An http based client.
- A differed client which selects between creating a grpc or http client, and will detect changes to the config and recreate the client.

As a result of these changes, the type of connection is explicit based on config.  If a grpc port is present, it will always use that connection, never trying to create an http client.

The actual code to create clients and make requests is mostly unchanged.
2019-10-31 16:05:28 -07:00
d579de63aa Update proto comments to reflect latest API changes () 2019-10-31 15:28:34 -07:00
797352a3fc Add Cacher, which invalidates a cache when config changes ()
I will use this in the evaluator_client, where we want to re-use a client if possible, but get a new client if the used values change. This solves the generic problem on a meta level, instead of having to manually remember and compare the config values used. It also prevents programming errors where a new config value is read, but the code doesn't properly detect if it has changed.

The ForceReset method will be used when the evaluator client has an error, so that the system will recover from a client which is stuck in an error state on the next call.

I anticipate there will be other places to use this inside open match.
2019-10-31 14:39:17 -07:00
68882a79bb Update release.md () 2019-10-31 14:06:14 -07:00
11bf81e146 Tutorial to build a matchmaker that uses multiple pools per match profile () 2019-10-31 13:46:38 -07:00
02aa992ac7 Fix cloudbuild () 2019-10-31 13:04:59 -07:00
f5b651669c Added protoc-gen-doc plugin to generate API references () 2019-10-31 11:34:24 -07:00
b9522a8bb5 Add a template for a basic OM based Matchmaker. The tutorials will use this as starting point. () 2019-10-31 10:26:55 -07:00
8c6fbcbe49 Update the MMF101 to be a mode based matchmaker () 2019-10-31 09:42:46 -07:00
99141686c9 Move Evaluator to tutorial namespace and enable tutorial configuration for Open Match () 2019-10-30 19:21:23 -07:00
3cf9c2ad6a Added jaeger sample configuration to the telemetry binder () 2019-10-30 18:10:04 -07:00
755c0e82f1 Fetch ignore list before querying for Tickets to fix a race where a ignored ticket could be returned as they move out of ignore list upon assignment () 2019-10-30 17:41:27 -07:00
18bc9f31fd Implement Tutorial for authoring a basic match function () 2019-10-30 17:23:05 -07:00
05325d3b77 Remane bindStackdriver to bindStackdriverMetrics () 2019-10-30 16:32:15 -07:00
3c7f73ed03 Install override yaml file by default when using helm upgrade () 2019-10-30 15:20:53 -07:00
525d35b341 Upgrade to helm3 () 2019-10-29 18:34:23 -07:00
d3e8638a3b Added Storage Dashboard in Grafana () 2019-10-29 17:26:15 -07:00
af19404eef Split up override configmap from open-match-core static yaml () 2019-10-29 16:55:22 -07:00
2f9e1c2209 Remove struct import from protos () 2019-10-29 14:00:02 -07:00
669f7d63b7 Remove evaluator config for default config yaml () 2019-10-29 13:14:10 -07:00
8740494f3e Added Makefile proxy and helm default configs for jaeger () 2019-10-28 17:36:40 -07:00
3899bd2fcd Have internal/config/config.go read in file through absolute path () 2019-10-28 13:20:34 -07:00
dac6ac141e Update RosterBased match function to not use the harness ()
Update RosterBased match function to not use the harness
2019-10-25 16:28:23 -07:00
c859e04bf9 Remove global configmap () 2019-10-25 15:44:15 -07:00
7a48467cb5 Config change first step () 2019-10-25 15:09:04 -07:00
74992cdf79 Added time metrics to statestore wrapper () 2019-10-25 11:36:35 -07:00
dd21919c00 Fix csharp dependency () 2019-10-25 10:34:09 -07:00
031b39e9c2 Added templates for bug/feature reports () 2019-10-24 11:19:01 -07:00
3f8f858d85 Update helm templates to follow k8s spec rules () 2019-10-24 10:53:32 -07:00
1dbd3a5a45 Create a privileged service account for Redis and disable THP to prevent Redis memory leaks () 2019-10-22 19:11:36 -07:00
fc94a7c451 Add csharp generated code and update .csproj dependency () 2019-10-22 15:28:13 -07:00
60d20ebae5 Update resource yamls to use k8s v1.16 API () 2019-10-21 11:16:07 -07:00
e369ac3c0b Update tutorial READMEs with more concrete steps ()
* Update tutorial READMEs with more concrete steps
2019-10-17 11:41:58 -07:00
2c35ecb304 Rename telemetry util function to match what it actually does ()
* Rename telemetry util function to match what it actually does

* Improve comments
2019-10-16 17:47:59 -07:00
7350524e78 Added open-match namespace in yaml installation files ()
* Create open-match namespace in yaml installation files when open-match-core is enabled

* Rename and comment
2019-10-16 16:13:38 -07:00
2aee5d128d Configure Open Match to improve scaling () 2019-10-15 14:28:35 -07:00
4773b7b7cf Added a Grafana dashboard to monitor Redis connection latency () 2019-10-15 13:37:26 -07:00
1abdace01e Pin Dockerfile base-build to go version 1.13.1. ()
I had a problem just now where my local go test would pass, but docker files would fail to build. My system had an old version of golang:latest cached, which failed to build properly due to missing a new method. So instead pin the dockerfile to a specific verison. This way builds will be more deterministic: If a new version of Go comes out, the new features won't work for anyone until this is updated, at which point everyone's local cache will be invalidated.
2019-10-14 18:32:25 -07:00
bbcf8d47b4 Update release template to install open match without telemetry services () 2019-10-14 15:05:26 -07:00
d65dee6be0 Change k8s service type into headless service and use DNS resolver to get endpoint ()
* Implement client side load balancing with DNS resolver for Open Match headless service deployment

* Update comments
2019-10-14 14:44:34 -07:00
02e6b3bbde Rename attribute to *_arg, FloatRangeFilter to DoubleRangeFilter ()
Part of 

Helps with  as the fields names not matching removes most incompatible query cases.
2019-10-14 13:16:31 -07:00
77090d1a5b Tutorial ()
* Tutorial skeleton

* Update

* Yet another update

* Add header
2019-10-14 12:20:43 -07:00
ce3a7bf389 Remove properties fields from messages.proto ()
Part of moving to the new API proposal: 
2019-10-11 14:09:38 -07:00
bcf710b755 Remove evaluator client test ()
Part of moving to the new API proposal: 

This didn't break earlier when it should have, because the test wasn't working.

As this is covered by the end to end tests anyways, delete.
2019-10-11 13:13:55 -07:00
2b7eec8c07 Remove index configuration ()
Part of moving to the new API proposal: 
2019-10-11 12:54:41 -07:00
99164df2db Have mmf harness pass extension instead of properties ()
Part of moving to the new API proposal: 
2019-10-11 12:00:35 -07:00
efa1ce5a0b Update telemetry/metrics to support adding histogram view ()
* Update telemetry/metrics to support adding histogram view

* Update comment
2019-10-11 11:42:48 -07:00
cb610a92b1 Define minimalistic pod resources to deploy sample mmf and evaluator ()
* Define minimalistic pod resources to deploy sample mmf and evaluator

* newline
2019-10-11 11:10:14 -07:00
89691b5512 Remove internal dependencies from the demo ()
* Remove internal dependencies from the demo
2019-10-10 19:32:08 -07:00
252d473d72 Generate helm charts at runtime and delete install/helm/open-match/charts repo ()
* Generate helm charts at runtime
2019-10-10 19:15:49 -07:00
56cfb8e66e Remove last references to ticket.properties ()
Part of moving to the new API proposal: 
2019-10-10 18:50:17 -07:00
5f32d4b765 Switch Default Evaluator to use proto any ()
Added a new proto to messages, DefaultEvaluationCriteria.

Reworked the default evaluator to use it.
Changed the pool mmf to output it.
2019-10-10 16:47:56 -07:00
658aee8874 Use SearchField's doubles for double indexing ()
Part of moving to the new API proposal: 

This replaces the double indexing, and fixes the spots which break because of it.
Future PRs will remove indexing and the passing of configuration that were because of it, and then also remove the properties altogether. (there's still a handful of places which use properties but don't actually use it for indexing.)
2019-10-10 15:54:33 -07:00
6ac7910fb1 Remove property usage from e2e/ticket_test ()
Part of moving to the new API proposal: 
2019-10-10 12:54:22 -07:00
fcf7c81c84 Commit missed proto build changes ()
Missed this with my previous change.
2019-10-09 18:30:14 -07:00
e3d630729c Replace boolean filter with tag filter ()
Part of moving to the new API proposal: 
2019-10-09 17:41:59 -07:00
da9d48ddb1 Remove unnecesssary properties and filters in demo ()
This was possible since the move to read all tickets with no filters. It simplifies the demo
complexity a bit.

Tangential, but useful to moving to the new API proposal: 
2019-10-09 12:05:47 -07:00
3727b0d5d8 Update third party code () 2019-10-08 19:06:57 -07:00
cc1b70dd2e Use SearchField's strings for string indexing ()
Part of moving to the new API proposal: 
2019-10-08 16:33:28 -07:00
91090af431 Remove outdated and unused filter package () 2019-10-08 15:58:56 -07:00
6661df62ae Adding Any fields to messages.proto ()
See  for detailed discussion.

Followup changes will involve wiring up the search_fields, then transitioning the existing tests and examples, then removing the old struct fields.
2019-10-08 15:36:33 -07:00
f63a93b139 Fix cloudbuild () 2019-10-07 16:39:08 -07:00
31648c35f3 Port over an end-to-end test with complete game logic to in-cluster test ()
* Port over an end-to-end test with complete logic to in-cluster test

* Fix discrepancy in MMF host name
2019-10-04 12:33:57 -07:00
e96a6e8af7 Reflect latest artifact changes in the release shell script () 2019-10-01 10:48:48 -07:00
d9912c3e28 DeleteFromIgnoreList when tickets got assigned or deleted ()
* DeleteFromIgnoreList when tickets got assigned or deleted
2019-09-30 18:28:10 -07:00
8933255ec2 Fix OpenConcensus backend_matches_fetched metric ()
* Fix open concensus backend_matches_fetched metric

* Update
2019-09-30 18:10:23 -07:00
3617d3cdbd Use StringEquals properly in e2e tests ()
* Use StringEquals properly in e2e tests
2019-09-30 17:57:26 -07:00
736a979b47 Fix create-gke-cluster command ()
* Fix create-gke-cluster command
2019-09-30 15:59:53 -07:00
aa99d7860e Add release note approval to release process. Improve ordering in release notes template () 2019-09-27 12:48:40 -07:00
22ad6fed6b HealthCheck workaround ()
* HealthCheck workaround

* Update
2019-09-25 15:23:42 -07:00
39e495512b Make CI compatible with go1.13 ()
* Make CI compatible with go1.13

* bump version
2019-09-25 10:48:59 -07:00
291e60a735 Fix Scale tests () 2019-09-23 16:20:53 -07:00
b29dfae9cf Reorder make rule dependencies to fix presubmit () 2019-09-20 16:02:15 -07:00
377b40041d Rename indice' const names to reflect their filter types and unify ticketIndice value ()
* Rename indice' names for testing to reflect their filter types

* Fix golangci error
2019-09-19 18:20:53 -07:00
6f7b7640c2 Pass synchronizer id on the context of the call to synchronizer ()
Pass synchronizer id on the context of the call to synchronizer
2019-09-19 16:01:47 -07:00
039eefb690 Open Match scale testing improvements ()
* Open Match scale testing improvements
2019-09-19 15:44:40 -07:00
5de0ae1fc4 Bump default ignore list ttl to 60seconds to give the backend sufficient time to allocate DGS () 2019-09-19 15:21:58 -07:00
1e5560603a Enable Synchronizer by default () 2019-09-18 11:53:20 -07:00
61449fe2cf Implement Roster based MMF that populates roster pools with tickets from the pools supplied. ()
* update

* Implement the Roster based match function for scale tests
2019-09-17 17:48:47 -07:00
21cf0697fe Implement test backend that will fetch matches, assign tickets and delete tickets at scale () 2019-09-17 17:14:50 -07:00
12e5a37816 Add end-to-end test for new filter types ()
* Add end-to-end test for new filter types
2019-09-17 16:25:09 -07:00
e658cc0d84 Add csproj baseline ()
* Add csproj baseline

* Automate CSharp packing via Docker

* Build csharp locally

* Rm dockerfile

* Modify gitignore
2019-09-17 16:09:41 -07:00
9e89735d79 Implement test frontend that creates tickets in Open Match continuously () 2019-09-17 15:47:40 -07:00
5cbbfef1cc Implement the profiles package that will be used by the scale backend to generate profiles for different scenarios for scale testing () 2019-09-17 15:14:10 -07:00
1c0e4ff94e Add implementation for Tickets library to generate fake tickets for scale test () 2019-09-17 11:00:41 -07:00
79862c9950 Add placeholder components for Open Match scale benchmarking () 2019-09-16 18:01:37 -07:00
8ac27d7975 Change protobuf namespace to openmatch ()
This resolves 

It would be very weird for other protobuf packages to be importing "api" for Open Match. This changes to a more reasonable unique name.

Eg, tensorflow uses the package "tensorflow" https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/protobuf/config.proto
2019-09-16 16:41:00 -07:00
86b8cb5aa8 Add string equals filtering and indexing ()
Part of implementing 
2019-09-16 15:54:41 -07:00
fdea3c8f1e Move gke-metadata-server workaround out from install/helm directory ()
* Move gke-metadata-server workaround out from install/helm directory
2019-09-16 11:50:17 -07:00
61a28df3e5 Stop using environment variables for Redis connection ()
* Stop using environment variables for Redis connection
2019-09-13 11:02:22 -07:00
13fe3fe5a9 Add CSharp namespace () 2019-09-12 09:53:36 -07:00
a674fb1c02 Add bool filtering and indexing ()
Add bool filtering and indexing
2019-09-10 14:51:05 -07:00
75ffc83b98 Rename Filter to FloatRangeFilter ()
This sets things up for other filter types.
2019-09-06 17:04:21 -07:00
7dc4de6a14 Store indexes used for a ticket, and use them to deindex ()
This has two primary advantages:
The redis key of the index can be decided at ticket index / query time. This is important for string equal indexing, where the plan is to concatenate the OM index name and the string value to form the redis key.
Improved correctness when indexes are changed: The ticket will now clean up the indexes it was created with, preventing old indices from existing after all the tickets that used them are gone.

This does add an extra read when deindexing a ticket, but I think the correctness improvement alone is worth that.

Other notes:
Turns out the indexes need to be in a list of interface{} to concatenate with the redis key for the cache, so I changed my mind about computing the list in extractIndexedFields. So extractIndexedFields instead just returns the map of index to values.

Improved a test's assertions by using ElementsMatch.
2019-09-06 16:06:21 -07:00
f02283e2a6 Add all tickets indexed, used on pools with no filters ()
Resolves 
2019-09-06 14:00:00 -07:00
d1fe7f1ac4 Improve synchronizer logging ()
* Improve synchronizer logging

* Improve synchronizer logging
2019-09-06 13:43:51 -07:00
84eb9b27ef Use config value for Redis hostname and port () 2019-09-06 13:18:44 -07:00
707de22912 Seperate redis and OM index concepts ()
> Currently OM filters directly match filtering fields in redis, and OM ticket properties directly map to values in redis. This change breaks that direct connection. In followup changes, I will be adding other index and filter types. They will be translated into redis sorted set values, so that conversion will take place within these methods. Eg, bool values will be turned into 0 and 1, and bool equal filters will do a range to capture those values.
> 
> This does a couple other minor things:
> 
> * Removes a test case that indexed fields have to be numbers, which is going to be wrong after other filter types are added anyways.
> * Adds a prefix to the redis key for the index. This will be important as other index types are added to avoid collisions.
2019-09-06 12:55:30 -07:00
780e3abf10 Fix demo bug () 2019-09-05 16:35:57 -07:00
524b7d333f Use secure websockets when demo page is on https ()
This fixes the scenario where the demo is behind an https proxy. In that scenario, it would
previously try to connect via unsecured websockets, which doesn't work. Specifically, this
is the case for Google Cloud Console's Web Preview.

Tested=Manually, bridging locally and also with the Cloud Console.
2019-09-05 09:22:40 -07:00
c544b9a239 Fix the namespace bug in install/yaml () 2019-09-03 23:57:21 -07:00
04b6f1a5ad Have filter tickets take pool instead of list of filters ()
Part of the work for 

This changes the API of FilterTickets to take a pool instead of filter list. Following the API
in the proposal, different filter types will be different fields on the Pool message.
2019-09-03 16:18:57 -07:00
13952ea54e Fix md-test by adding whitelist value for swagger.io () 2019-09-03 16:00:48 -07:00
a61f4a643e Align Kubernetes API versions and Update the rest of the module versions () 2019-08-30 14:53:00 -07:00
949fa28505 Evaluator http test and implementation ()
* Change evaluator API from unary to bidirectional streaming
2019-08-23 16:24:04 -07:00
85cc481f5d Change synchronizer API from unary to bidirectional streaming ()
* Change synchronizer API from unary to bidirectional streaming

* bug fix

* reformat

* Update

* Update

* update
2019-08-22 16:20:29 -07:00
c3cbcd7625 Change evaluator API from unary to bidirectional streaming and disable HTTP support for the evaluator ()
* Change evaluator API from unary to bidirectional streaming

* Bug fix

* Yet another bug fix

* Update

* Update
2019-08-22 15:37:51 -07:00
e01fc12549 Reformat install/terraform () 2019-08-22 13:25:15 -07:00
e1682100fa Fix swaggerdoc error () 2019-08-22 13:07:17 -07:00
603aef207f Remove dependency on gogo/protobuf () 2019-08-22 12:48:13 -07:00
baf403ac44 Replace json with jsonpb () 2019-08-22 12:32:55 -07:00
b1da77eaba Change backend.FetchMatches from unary to streaming () 2019-08-16 14:51:10 -07:00
bb82a397d2 Ignore globals when linting everywhere.
The exclusions list is ever growing because there are many valid
use cases for global variables. The standard library uses them
all over the place. Removing the check, and instead relying on
code review to spot bad uses of globals.
2019-08-16 11:55:12 -07:00
abd2c1434c Explicitly ignore gateway files in golangci () 2019-08-16 11:20:16 -07:00
bc9dc27210 Suppress golangci error ()
* Turn off checking shadowing

* Suppress golangci output
2019-08-16 10:11:10 -07:00
084461d387 Change mmf API from unary call to streaming ()
* Test to replicate the grpcLimit error

* Change mmf from unary to streaming

* Resolve comment

* Resolve comments
2019-08-15 16:43:22 -07:00
bc7d014db6 Express open-match-build infrastructure as Terraform template ()
* Replicate infrastructure configs in terraform

* Express open-match-build infrastructure as Terraform template

* Import changes
2019-08-15 12:56:45 -07:00
230ae76bb4 Set default logging.rpc value to false ()
* Fix rpc enabled config alias

* Set default logging.rpc value to false
2019-08-15 12:35:59 -07:00
ebbe5aa6ce Add a breaking API change issue template () 2019-08-15 11:54:19 -07:00
9b350c690c Disable stress testing in CI () 2019-08-15 11:26:07 -07:00
80b817f488 Fix cloudbuild dependency () 2019-08-15 10:41:11 -07:00
df7021de1b Add comments for values.yaml file in the parent chart ()
* Checkpoint

* Comments for values.yaml file
2019-08-13 11:27:53 -07:00
5c8f218000 Remove CI subnet workaround ()
* Remove CI subnet workaround

* Apply changes
2019-08-06 13:54:19 -07:00
3f538df971 Fix Makefile targets ()
* Makefile dependency fix

* Resolve comments
2019-08-05 14:44:05 -07:00
1e856658c9 Fix proto file's go package. ()
Fixes 

Also removed redundant instruction to build messages.pb.go, and unused instruction to build message.pb.gw.go.
2019-08-05 11:10:40 -07:00
eb6697052d Reflects IAM role changes in terraform config ()
* Reflects IAM role changes in terraform config

* Resolve comments

* Resolve comments

* Resolve comments

* Update
2019-08-02 18:26:33 -07:00
31d3464a31 Helm README ()
* Helm README

* Indentation

* Review comments
2019-08-02 17:54:19 -07:00
c96b65d52b Make load testing upload test results to GCS ()
* Delete old helm config and use new config in CI

* Fix tiller dependency

* Fix cloudbuild

* fix yaml postfix

* Make stress test upload results to GCS

* hi

* Update tgz

* Fix bad merge

* Enable test

* Update charts

* Done

* Test

* Fix

* Fix gcpProjectId

* Update charts

* Update

* Fix

* Update

* Add time
2019-08-02 17:08:51 -07:00
9d601351cc Make synchronizer proto properly internal ()
* Move generated files from internal/pb to internal/ipb to avoid name conflict.
* No longer server / generate http/json endpoint nor the swagger files.
* The proto package is now an internal package.

resolves 
2019-08-02 16:26:37 -07:00
7272ca8b93 Let end-to-end tests run in-cluster ()
* Replace LoadBalancer in CI with NodePort

* Fix
2019-08-02 15:18:12 -07:00
b463d2e0fd Remove unnecessary dependencies to speed up CI () 2019-08-02 14:57:58 -07:00
07da543f8e Autogenerate image commands based on a single list ()
With this change, anything added to the cmd/ folder is automatically
made into an image and included the image commands. Additional
images are also included. This does remove some commands that are
for pushing specific sets of images, but it seems rare/never (asking yfei1
and sawagh) that anyone is actually using these commands.

Includes some commenting to hopefully alleviate the magic being added.
2019-08-02 14:38:52 -07:00
0d54c39828 Update instructions for release-0.6 () 2019-08-02 14:09:16 -07:00
5469c8bc69 Unify SHORT_SHA and VERSION_SUFFIX () 2019-08-02 11:03:52 -07:00
c837211cd1 Skip using PodSecurityPolicy in CI runs ()
* Skip psp in CI run

* Update

* Works

* metadataserver psp

* Update chart
2019-08-02 10:34:40 -07:00
5729e72214 Improve context propagation for synchronizer () 2019-08-01 15:13:23 -07:00
66910632da Distinguish RELEASE_NAME and CHART_NAME in Makefile () 2019-08-01 12:54:52 -07:00
c832074112 Makefile bug fixes ()
* Bug fixes
2019-07-31 17:27:11 -07:00
a6d526b36b Remove unused app engine and html makefile stuff ()
I assume this was left over from the website being in this repo.
2019-07-31 16:10:12 -07:00
13e017ba65 Remove image artifacts from cloudbuild ()
* Remove image artifacts from cloudbuild

* Update cloudbuild.yaml
2019-07-31 14:34:33 -07:00
3784300d22 Payload logging () 2019-07-31 12:53:59 -07:00
31fd18e39b CI Reap Namespace () 2019-07-31 12:32:31 -07:00
a54d1fcf21 Let CI runs in one cluster under unique namespaces () 2019-07-31 12:11:37 -07:00
72a435758e Replace all-proto with variables containing all proto files ()
This moves the all-proto target from being phony, to containing a concrete lists of targets. This means other targets can depend on $(ALL_PROTO) without becoming phony itself.
2019-07-30 14:33:09 -07:00
6848fa71c2 Remove duplicate step from cloudbuild () 2019-07-30 13:40:29 -07:00
987d90cc44 Have the demo use the template Dockerfile and sit in cmd ()
This also gives it a more distinguished name as there are likely to be other demos (with other components) in the near future. It is also sitting in a larger namespace (the cmd folder) which helps too.
2019-07-29 22:12:55 -07:00
baf943fdd3 Fix logger name in the appmain.go () 2019-07-29 15:53:12 -07:00
c7ce1b047b Use templated Dockerfile and make for cmd images ()
This leads up to being able to swap out the standard dockerfile for one which uses a locally built binary. Also is just cleaner as there is less redundancy across dockerfiles.

Disables cgo for builds, as it doesn't work with distroless.

Stops relying on phony protos target which causes extra rebuilds of all the protos. (Using variable expansion should fix this issue in a seperate PR)

All commands are now named run, because ARG arbitrarily doesn't work for ENTRYPOINT.
2019-07-26 18:10:59 -07:00
36a194e761 Unify server setup and call log configuration () 2019-07-26 13:26:02 -07:00
605511d177 Enable workload identity in terraform and Makefile ()
* Enable workload identity in terraform and Makefile

* Applied changes and added tftstate file
2019-07-26 11:28:04 -07:00
2a08732508 Merge netlistener into util package. () 2019-07-26 08:53:21 -07:00
e1c2b96cb5 Add HorizontalPodAutoscaler policies. () 2019-07-26 07:53:57 -07:00
1bd84355b7 Replace context.Background() in tests to prepare for multi-tenancy. () 2019-07-26 07:13:09 -07:00
a9014fbf78 Fix make test targets () 2019-07-26 01:12:05 -07:00
8050c61618 Add helm wait and disable verify unreliable URLs. () 2019-07-25 13:43:51 -07:00
8b765871c4 Add HTTP client logging support and flags for test. () 2019-07-24 14:11:42 -07:00
88786ecbd1 Breakout synchronizer state into it's own struct. () 2019-07-24 11:25:23 -07:00
f41c175f29 Expand hostname:port and hostname in certgen. () 2019-07-23 15:16:09 -07:00
3607809371 Delete old helm config and use new config for CI ()
* Delete old helm config and use new config in CI

* Fix dependency

* Bug fixes

* Fix

* Disable tls
2019-07-23 14:36:24 -07:00
d21ae712a7 Add build/cmd to Makefile ()
This is part of the larger goal of simplifying and speeding up builds.

General strategy here:

1. Add make build/cmd target, to build what is currently in /cmd. <- this PR
2. In the basebuild Dockerfile, run make build/cmd, and replace the seperate Dockerfiles for the services in cmd/ with one Dockerfile (with an arg for which service) which copies from build/cmd// to the Dockerfile and runs it.
3. Reconcile the Docker images not included in the /cmd to follow this pattern as well (in individual PRs.)
4. Clean up redundant ways to build things.
5. (If it improves speed) add local build variation for faster builds.
2019-07-22 14:21:06 -07:00
f3f1908318 Add /help, /configz, /debug/* pages. () 2019-07-17 07:33:09 -07:00
9cb4a9ce6e Remove cloudbuild artifacts () 2019-07-17 07:00:29 -07:00
8dad7fd7d0 Configure helm install using subcharts ()
* Split up charts

* Fix build/chart/

* Revert Makefile

* Bug fixes

* Checkpoint

* Update

* Revert Makefile
2019-07-16 15:35:52 -07:00
f70cfee14a Cache dependency downloads by adding only go module to Dockerfile ()
First copy only the go.sum and go.mod then download dependencies. Docker
caching is [in]validated by the input files changes. So when the dependencies
for the project don't change, the previous image layer can be re-used. go.sum
is included as its hashing verifies the expected files are downloaded.

I'm ignoring cases where the go.mod is missing a dep for now. Later go commands will
fetch the missing deps, and they should make their way into go.mod sooner rather than later.
If it's a mess, it can be cleaned up later.

The time comparison of building all images from before and after is:
clean build: 7m22s -> 7m22s
after small change to demo: 5m59 -> 5m7s

So no speed increase for purely fresh builds (as expected), but saves a minute when deps haven't changed from the last build.
2019-07-16 14:38:01 -07:00
36f92b4336 Instrument HTTP clients and servers. () 2019-07-16 12:54:19 -07:00
164dfdde67 Open locally serving TCP ports in unit tests to avoid triggering firewall screens. () 2019-07-16 11:32:12 -07:00
c0d6531f3f Simplify HTTP client construction. () 2019-07-16 10:01:56 -07:00
321 changed files with 27287 additions and 7619 deletions
.dockerignore
.github/ISSUE_TEMPLATE
.gitignore.golangci.yamlDockerfile.base-buildDockerfile.ciDockerfile.cmdMakefile
api
cloudbuild.yaml
cmd
backend
demo-first-match
frontend
mmlogic
scale-backend
scale-frontend
swaggerui
synchronizer
csharp/OpenMatch
docs/governance/templates
examples
go.modgo.sum
install
internal
pkg
test
third_party
google/api
protoc-gen-swagger/options
swaggerui
tools
tutorials

@ -18,6 +18,7 @@
*.exe
*.exe~
*.dll
*.nupkg
*.so
*.dylib
@ -51,6 +52,8 @@ detritus/
# Dotnet Core ignores
*.swp
*.pdb
*.deps.json
*.*~
project.lock.json
.DS_Store
@ -81,6 +84,9 @@ bld/
msbuild.log
msbuild.err
msbuild.wrn
csharp/OpenMatch/obj
Chart.lock
# Visual Studio 2015
.vs/
@ -121,6 +127,7 @@ cmd/swaggerui/swaggerui
tools/certgen/certgen
examples/demo/demo
examples/functions/golang/soloduel/soloduel
examples/functions/golang/rosterbased/rosterbased
examples/functions/golang/pool/pool
examples/evaluator/golang/simple/simple
tools/reaper/reaper
@ -130,3 +137,6 @@ build/
# Secrets Directories
install/helm/open-match/secrets/
# Helm tar charts
install/helm/open-match/charts/

25
.github/ISSUE_TEMPLATE/apichange.md vendored Normal file

@ -0,0 +1,25 @@
---
name: Breaking API change
about: Details of a breaking API change proposal.
title: 'API change: <>'
labels: breaking api change
assignees: ''
---
## Overview
<High level description of this change>
## Motivation
<What is the primary motivation for this API change>
## Impact
<What usage does this impact? Add details here such that a consumer of Open
Match API can clearly tell if this will impact them>
## Change Proto
<Add snippet of the proposed change proto>

30
.github/ISSUE_TEMPLATE/bugreport.md vendored Normal file

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: kind/bug
assignees: ''
---
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!
If the matter is security related, please disclose it privately via
-->
**What happened**:
**What you expected to happen**:
**How to reproduce it (as minimally and precisely as possible)**:
**Anything else we need to know?**:
**Output of `kubectl version`**:
**Cloud Provider/Platform (AKS, GKE, Minikube etc.)**:
**Open Match Release Version**:
**Install Method(yaml/helm):**:

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: kind/feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

@ -1,5 +1,5 @@
---
name: release
name: Publish a Release
about: Instructions and checklist for creating a release.
title: 'Release X.Y.Z-rc.N'
labels: kind/release
@ -8,88 +8,98 @@ assignees: ''
# Open Match Release Process
Follow these instructions to create an Open Match release. The output of the
Follow these instructions to create an Open Match release. The output of the
release process is new images and new configuration.
## Getting setup
*note: the commands below are pasted from the 0.5 release. make the necessary
changes to match your naming & environment.*
**NOTE: The instructions below are NOT strictly copy-pastable and assume 0.5**
**release. Please update the version number for your commands.**
The Git flow for pushing a new release is similar to the development process
but there are some small differences.
**1. Clone your fork of the Open Match repository.**
### 1. Clone Repository
```shell
# Clone your fork of the Open Match repository.
git clone git@github.com:afeddersen/open-match.git
```
**2. Move into the new open-match directory.**
```shell
# Change directory to the git repository.
cd open-match
```
**3. Configure a remote that points to the upstream repository. This is required to sync changes you make in a fork with the original repository. Note: Upstream is the gatekeeper of the project or the source of truth to which you wish to contribute.**
```shell
# Add a remote, you'll be pushing to this.
git remote add upstream https://github.com/googleforgames/open-match.git
```
**3. Fetch the branches and their respective commits from the upstream repo.**
### 2. Release Branch
If you're creating the first release of the version, that would be `0.5.0-rc.1`
then you'll need to create the release branch.
```shell
git fetch upstream
# Create a local release branch.
git checkout -b release-0.5 upstream/master
# Push the branch upstream.
git push upstream release-0.5
```
**4. Create a local release branch that tracks upstream and check it out.**
otherwise there should already be a `release-0.5` branch so run,
```shell
# Checkout the release branch.
git checkout -b release-0.5 upstream/release-0.5
```
**NOTE: The branch name must be in the format, `release-X.Y` otherwise**
**some artifacts will not be pushed.**
## Releases & Versions
Open Match uses Semantic Versioning 2.0.0. If you're not familiar please
Open Match uses Semantic Versioning 2.0.0. If you're not familiar please
see the documentation - [https://semver.org/](https://semver.org/).
Full Release / Stable Release:
* The final software product. Stable, reliable, etc...
* Naming example: 1.0.0
* The final software product. Stable, reliable, etc...
* Example: 1.0.0, 1.1.0
Release Candidate (RC):
* A release candidate (RC) is a version with the potential to be the final
product but it hasn't validated by automated and/or manual tests.
* Naming example: 1.0.0-rc.1
* Example: 1.0.0-rc.1
Hot Fixes:
* Code developed to correct a major software bug or fault
that's been discovered after the full release.
* Naming example: 1.0.1
* Example: 1.0.1
Preview:
* Rare, a one off release cut from the master branch to provide early access
to APIs or some other major change.
* **NOTE: There's no branch for this release.**
* Example: 0.5-preview.1
**NOTE: Semantic versioning is enforced by `go mod`. A non-compliant version**
**tag will cause `go get` to break for users.**
# Detailed Instructions
## Find and replace
Below this point you will see {version} used as a placeholder for future
releases. Find {version} and replace with the current release (e.g. 0.5.0)
releases. Find {version} and replace with the current release (e.g. 0.5.0)
## Create a release branch in the upstream repository
**Note: This step is performed by the person who starts the release. It is
only required once.**
- [ ] Create the branch in the **upstream** repository. It should be named
release-X.Y. Example: release-0.5. At this point there's effectively a code
freeze for this version and all work on master will be included in a future
version. If you're on the branch that you created in the *getting setup*
version. If you're on the branch that you created in the *getting setup*
section above you should be able to push upstream.
```shell
@ -98,22 +108,21 @@ git push origin release-0.5
- [ ] Announce a PR freeze on release-X.Y branch on [open-match-discuss@](mailing-list-post).
- [ ] Open the [`Makefile`](makefile-version) and change BASE_VERSION entry.
- [ ] Open the [`install/helm/open-match/Chart.yaml`](om-chart-yaml-version) and [`install/helm/open-match-example/Chart.yaml`](om-example-chart-yaml-version) and change the `appVersion` and `version` entries.
- [ ] Open the [`install/helm/open-match/values.yaml`](om-values-yaml-version) and [`install/helm/open-match-example/values.yaml`](om-example-values-yaml-version) and change the `tag` entries.
- [ ] Open the [`site/config.toml`] and change the `release_branch` and `release_version` entries.
- [ ] Open the [`install/helm/open-match/Chart.yaml`](om-chart-yaml-version) and change the `appVersion` and `version` entries.
- [ ] Open the [`install/helm/open-match/values.yaml`](om-values-yaml-version) and change the `tag` entries.
- [ ] Open the [`cloudbuild.yaml`] and change the `_OM_VERSION` entry.
- [ ] Run `make clean release`
- [ ] There might be additional references to the old version but be careful not to change it for places that have it for historical purposes.
- [ ] Run `make release`
- [ ] Create a PR with the changes and include the release candidate name.
- [ ] Go to [open-match-build](https://pantheon.corp.google.com/cloud-build/triggers?project=open-match-build) and update all the triggers' `_GCB_LATEST_VERSION` value to the `X.Y` of the release. This value should only increase as it's used to determine the latest stable version.
- [ ] Merge your changes once the PR is approved.
## Complete Milestone
**Note: This step is performed by the person who starts the release. It is
**Note: This step is performed by the person who starts the release. It is
only required once.**
- [ ] Create the next [version milestone](https://github.com/googleforgames/open-match/milestones) and use [semantic versioning](https://semver.org/) when naming it to be consistent with the [Go community](https://blog.golang.org/versioning-proposal).
- [ ] Create a *draft* [release](https://github.com/googleforgames/open-match/releases).
- [ ] Create a *draft* [release](https://github.com/googleforgames/open-match/releases). Note that github has both "Pre-release" and "draft" as different concepts for a release. Until the release is finalized, only use "Save draft", and do not use "Publish release".
- [ ] Use the [release template](https://github.com/googleforgames/open-match/blob/master/docs/governance/templates/release.md)
- [ ] `Tag` = v{version}. Example: v0.5.0. Append -rc.# for release candidates. Example: v0.5.0-rc.1.
- [ ] `Target` = release-X.Y. Example: release-0.5.
@ -138,9 +147,17 @@ TODO: Add guidelines for labeling issues.
- [ ] Run `./docs/governance/templates/release.sh {source version tag} {version}` to copy the images to open-match-public-images.
- [ ] If this is a new minor version in the newest major version then run `./docs/governance/templates/release.sh {source version tag} latest`.
- [ ] Copy the files from `build/release/` generated from `make release` to the release draft you created. You can drag and drop the files using the Github UI.
- [ ] Run `make delete-gke-cluster create-gke-cluster` and run through the instructions under the [README](readme-deploy), verify the pods are healthy. You'll need to adjust the path to the `build/release/install.yaml` and `build/release/install-demo.yaml` in your local clone since you haven't published them yet.
- [ ] Open the [`README.md`](readme-deploy) update the version references and submit. (Release candidates can ignore this step.)
- [ ] Publish the [Release](om-release) in Github.
- [ ] Run proto-gen-doc to update API references in open-match-docs repo.
- [ ] Update [Slack invitation link](https://slack.com/help/articles/201330256-invite-new-members-to-your-workspace#share-an-invite-link) in [open-match.dev](https://open-match.dev/site/docs/contribute/#get-involved).
- [ ] Test Open Match installation under GKE and Minikube enviroment and make sure the first match example works.
- [ ] Update usage requirements in the Installation doc - e.g. supported minikube version, kubectl version, golang version, etc.
## Finalize
- [ ] Save the release as a draft.
- [ ] Circulate the draft release to active contributors. Where reasonable, get everyone's ok on the release notes before continuing.
- [ ] Publish the [Release](om-release) in Github. This will notify repository watchers.
## Announce
@ -151,9 +168,7 @@ TODO: Add guidelines for labeling issues.
[mailing-list-post]: https://groups.google.com/forum/#!newtopic/open-match-discuss
[release-template]: https://github.com/googleforgames/open-match/blob/master/docs/governance/templates/release.md
[makefile-version]: https://github.com/googleforgames/open-match/blob/master/Makefile#L53
[om-example-chart-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match/Chart.yaml#L16
[om-example-values-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match/values.yaml#L16
[om-example-chart-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match-example/Chart.yaml#L16
[om-example-values-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match-example/values.yaml#L16
[om-chart-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match/Chart.yaml#L16
[om-values-yaml-version]: https://github.com/googleforgames/open-match/blob/master/install/helm/open-match/values.yaml#L16
[om-release]: https://github.com/googleforgames/open-match/releases/new
[readme-deploy]: https://github.com/googleforgames/open-match/blob/master/README.md#deploy-to-kubernetes

9
.gitignore vendored

@ -16,6 +16,7 @@
*.exe
*.exe~
*.dll
*.nupkg
*.so
*.dylib
@ -49,6 +50,8 @@ detritus/
# Dotnet Core ignores
*.swp
*.pdb
*.deps.json
*.*~
project.lock.json
.DS_Store
@ -79,6 +82,8 @@ bld/
msbuild.log
msbuild.err
msbuild.wrn
csharp/OpenMatch/obj
Chart.lock
# Visual Studio 2015
.vs/
@ -118,9 +123,13 @@ cmd/swaggerui/swaggerui
tools/certgen/certgen
examples/demo/demo
examples/functions/golang/soloduel/soloduel
examples/functions/golang/rosterbased/rosterbased
examples/functions/golang/pool/pool
examples/evaluator/golang/simple/simple
tools/reaper/reaper
# Secrets Directories
install/helm/open-match/secrets/
# Helm tar charts
install/helm/open-match/charts/

@ -16,6 +16,8 @@
# with their default values.
# https://github.com/golangci/golangci-lint#config-file
service:
golangci-lint-version: 1.18.0
# options for analysis running
run:
@ -45,7 +47,7 @@ run:
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
skip-files:
skip-files: '.*\.gw\.go'
# output configuration options
output:
@ -165,18 +167,21 @@ linters-settings:
linters:
enable-all: true
disable:
- goimports
- stylecheck
- gocritic
- dupl
- funlen
- gochecknoglobals
- goconst
- gocritic
- gocyclo
- gosec
- lll
- staticcheck
- scopelint
- prealloc
- gofmt
- goimports
- gosec
- interfacer # deprecated - "A tool that suggests interfaces is prone to bad suggestions"
- lll
- prealloc
- scopelint
- staticcheck
- stylecheck
#linters:
# enable-all: true
@ -191,42 +196,11 @@ issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: internal[/\\]config[/\\]
linters:
- gochecknoglobals
- path: consts\.go
linters:
- gochecknoglobals
# Exclude some linters from running on test files
- path: _test\.go
linters:
- errcheck
- bodyclose
# The following are allowed global variable patterns.
# Generally it's ok to have constants or variables that effectively act as constants such as a static logger or flag values.
# The filters below specify the source code pattern that's allowed when declaring a global
# 'source: "flag."' will match 'var destFlag = flag.String("dest", "", "")'
- source: "flag."
linters:
- gochecknoglobals
- source: "telemetry."
linters:
- gochecknoglobals
- source: "View."
linters:
- gochecknoglobals
- source: "tag."
linters:
- gochecknoglobals
- source: "logrus."
linters:
- gochecknoglobals
- source: "stats."
linters:
- gochecknoglobals
- source: "serviceAddressList"
linters:
- gochecknoglobals
# Exclude known linters from partially hard-vendored code,
# which is impossible to exclude via "nolint" comments.

@ -12,9 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM golang:latest
# When updating Go version, update Dockerfile.ci, Dockerfile.base-build, and go.mod
FROM golang:1.13.1
ENV GO111MODULE=on
WORKDIR /go/src/open-match.dev/open-match
COPY . .
# First copy only the go.sum and go.mod then download dependencies. Docker
# caching is [in]validated by the input files changes. So when the dependencies
# for the project don't change, the previous image layer can be re-used. go.sum
# is included as its hashing verifies the expected files are downloaded.
COPY go.sum go.mod ./
RUN go mod download
COPY . .

@ -15,7 +15,7 @@
FROM debian
RUN apt-get update
RUN apt-get install -y -qq git make python3 virtualenv curl sudo unzip apt-transport-https ca-certificates curl software-properties-common gnupg2 bc
RUN apt-get install -y -qq git make python3 virtualenv curl sudo unzip apt-transport-https ca-certificates curl software-properties-common gnupg2
# Docker
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
@ -34,11 +34,13 @@ RUN export CLOUD_SDK_REPO="cloud-sdk-stretch" && \
apt-get update -y && apt-get install google-cloud-sdk google-cloud-sdk-app-engine-go -y -qq
# Install Golang
# https://github.com/docker-library/golang/blob/fd272b2b72db82a0bd516ce3d09bba624651516c/1.12/stretch/Dockerfile
# https://github.com/docker-library/golang/blob/master/1.13/stretch/Dockerfile
RUN mkdir -p /toolchain/golang
WORKDIR /toolchain/golang
RUN sudo rm -rf /usr/local/go/
RUN curl -L https://storage.googleapis.com/golang/go1.12.6.linux-amd64.tar.gz | sudo tar -C /usr/local -xz
# When updating Go version, update Dockerfile.ci, Dockerfile.base-build, and go.mod
RUN curl -L https://golang.org/dl/go1.13.1.linux-amd64.tar.gz | sudo tar -C /usr/local -xz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH

@ -14,20 +14,24 @@
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/minimatch/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
WORKDIR /go/src/open-match.dev/open-match
ARG IMAGE_TITLE
RUN make "build/cmd/${IMAGE_TITLE}"
FROM gcr.io/distroless/static:nonroot
ARG IMAGE_TITLE
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/minimatch/minimatch /app/
ENTRYPOINT ["/app/minimatch"]
COPY --from=builder --chown=nonroot "/go/src/open-match.dev/open-match/build/cmd/${IMAGE_TITLE}/" "/app/"
ENTRYPOINT ["/app/run"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Mini Match"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md

689
Makefile

File diff suppressed because it is too large Load Diff

@ -6,4 +6,10 @@ gRPC has first-class support for [many languages](https://grpc.io/docs/) and pro
For HTTP/HTTPS Open Match uses a gRPC proxy to serve the API. Since HTTP does not provide a structure for request/responses we use Swagger to provide a schema. You can view the Swagger docs for each service in this directory's `*.swagger.json` files. In addition each server will host it's swagger doc via `GET /swagger.json` if you want to dynamically load them at runtime.
Lastly, Open Match supports insecure and TLS mode for serving the API. It's strongly preferred to use TLS mode in production but insecure mode can be used for test and local development. To help with certificates management see `tools/certgen` to create self-signed certificates.
Lastly, Open Match supports insecure and TLS mode for serving the API. It's strongly preferred to use TLS mode in production but insecure mode can be used for test and local development. To help with certificates management see `tools/certgen` to create self-signed certificates.
# Open Match API Development Guide
Open Match proto comments follow the same format as [this file](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/example/example.proto)
If you plan to change the proto definitions, please update the comments and run `make api/api.md` to reflect the latest changes in open-match-docs.

@ -13,8 +13,9 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "api/messages.proto";
import "google/api/annotations.proto";
@ -54,8 +55,7 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
// https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/proto/examplepb/a_bit_of_everything.proto
};
// Configuration for the Match Function to be triggered by Open Match to
// generate proposals.
// FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF
message FunctionConfig {
string host = 1;
int32 port = 2;
@ -67,45 +67,43 @@ message FunctionConfig {
}
message FetchMatchesRequest {
// Configuration of the MatchFunction to be executed for the given list of MatchProfiles
// FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF
FunctionConfig config = 1;
// MatchProfiles for which this MatchFunction should be executed.
// MatchProfiles that will be sent to thhe MMF specified in the FunctionConfig.
repeated MatchProfile profiles = 2;
}
message FetchMatchesResponse {
// Result Match for the requested MatchProfile.
// Note that OpenMatch will validate the proposals, a valid match should contain at least one ticket.
repeated Match matches = 1;
// A Match generated by the user-defined MMF with the specified MatchProfiles.
// A valid Match response will contain at least one ticket.
Match match = 1;
}
message AssignTicketsRequest {
// List of Ticket IDs for which the Assignment is to be made.
// TicketIds is a list of strings representing Open Match generated Ids which apply to an Assignment.
repeated string ticket_ids = 1;
// Assignment to be associated with the Ticket IDs.
// An Assignment specifies game connection related information to be associated with the TicketIds.
Assignment assignment = 2;
}
message AssignTicketsResponse {}
// The service implementing the Backent API that is called to generate matches
// and make assignments for Tickets.
// The Backent service implements APIs to generate matches and handle ticket assignments.
service Backend {
// FetchMatch triggers execution of the specfied MatchFunction for each of the
// specified MatchProfiles. Each MatchFunction execution returns a set of
// proposals which are then evaluated to generate results. FetchMatch method
// streams these results back to the caller.
rpc FetchMatches(FetchMatchesRequest) returns (FetchMatchesResponse) {
// FetchMatches triggers a MatchFunction with the specified MatchProfiles, while each MatchProfile
// returns a set of match proposals. FetchMatches method streams the results back to the caller.
// FetchMatches immediately returns an error if it encounters any execution failures.
// - If the synchronizer is enabled, FetchMatch will then call the synchronizer to deduplicate proposals with overlapped tickets.
rpc FetchMatches(FetchMatchesRequest) returns (stream FetchMatchesResponse) {
option (google.api.http) = {
post: "/v1/backend/matches:fetch"
body: "*"
};
}
// AssignTickets sets the specified Assignment on the Tickets for the Ticket
// IDs passed.
// AssignTickets overwrites the Assignment field of the input TicketIds.
rpc AssignTickets(AssignTicketsRequest) returns (AssignTicketsResponse) {
option (google.api.http) = {
post: "/v1/backend/tickets:assign"

@ -26,13 +26,13 @@
"paths": {
"/v1/backend/matches:fetch": {
"post": {
"summary": "FetchMatch triggers execution of the specfied MatchFunction for each of the\nspecified MatchProfiles. Each MatchFunction execution returns a set of\nproposals which are then evaluated to generate results. FetchMatch method\nstreams these results back to the caller.",
"summary": "FetchMatches triggers a MatchFunction with the specified MatchProfiles, while each MatchProfile \nreturns a set of match proposals. FetchMatches method streams the results back to the caller.\nFetchMatches immediately returns an error if it encounters any execution failures.\n - If the synchronizer is enabled, FetchMatch will then call the synchronizer to deduplicate proposals with overlapped tickets.",
"operationId": "FetchMatches",
"responses": {
"200": {
"description": "A successful response.",
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/definitions/apiFetchMatchesResponse"
"$ref": "#/x-stream-definitions/openmatchFetchMatchesResponse"
}
},
"404": {
@ -48,7 +48,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiFetchMatchesRequest"
"$ref": "#/definitions/openmatchFetchMatchesRequest"
}
}
],
@ -59,13 +59,13 @@
},
"/v1/backend/tickets:assign": {
"post": {
"summary": "AssignTickets sets the specified Assignment on the Tickets for the Ticket\nIDs passed.",
"summary": "AssignTickets overwrites the Assignment field of the input TicketIds.",
"operationId": "AssignTickets",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiAssignTicketsResponse"
"$ref": "#/definitions/openmatchAssignTicketsResponse"
}
},
"404": {
@ -81,7 +81,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiAssignTicketsRequest"
"$ref": "#/definitions/openmatchAssignTicketsRequest"
}
}
],
@ -92,7 +92,7 @@
}
},
"definitions": {
"apiAssignTicketsRequest": {
"openmatchAssignTicketsRequest": {
"type": "object",
"properties": {
"ticket_ids": {
@ -100,69 +100,44 @@
"items": {
"type": "string"
},
"description": "List of Ticket IDs for which the Assignment is to be made."
"description": "TicketIds is a list of strings representing Open Match generated Ids which apply to an Assignment."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment to be associated with the Ticket IDs."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment specifies game connection related information to be associated with the TicketIds."
}
}
},
"apiAssignTicketsResponse": {
"openmatchAssignTicketsResponse": {
"type": "object"
},
"apiAssignment": {
"openmatchAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
"description": "An Assignment represents a game server assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiFetchMatchesRequest": {
"openmatchDoubleRangeFilter": {
"type": "object",
"properties": {
"config": {
"$ref": "#/definitions/apiFunctionConfig",
"title": "Configuration of the MatchFunction to be executed for the given list of MatchProfiles"
},
"profiles": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatchProfile"
},
"description": "MatchProfiles for which this MatchFunction should be executed."
}
}
},
"apiFetchMatchesResponse": {
"type": "object",
"properties": {
"matches": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "Result Match for the requested MatchProfile.\nNote that OpenMatch will validate the proposals, a valid match should contain at least one ticket."
}
}
},
"apiFilter": {
"type": "object",
"properties": {
"attribute": {
"double_arg": {
"type": "string",
"description": "Name of the ticket attribute this Filter operates on."
"description": "Name of the ticket's search_fields.double_args this Filter operates on."
},
"max": {
"type": "number",
@ -175,9 +150,34 @@
"description": "Minimum value. Defaults to 0."
}
},
"description": "A hard filter used to query a subset of Tickets meeting the filtering\ncriteria."
"title": "Filters numerical values to only those within a range.\n double_arg: \"foo\"\n max: 10\n min: 5\nmatches:\n {\"foo\": 5}\n {\"foo\": 7.5}\n {\"foo\": 10}\ndoes not match:\n {\"foo\": 4}\n {\"foo\": 10.01}\n {\"foo\": \"7.5\"}\n {}"
},
"apiFunctionConfig": {
"openmatchFetchMatchesRequest": {
"type": "object",
"properties": {
"config": {
"$ref": "#/definitions/openmatchFunctionConfig",
"title": "FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF"
},
"profiles": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchMatchProfile"
},
"description": "MatchProfiles that will be sent to thhe MMF specified in the FunctionConfig."
}
}
},
"openmatchFetchMatchesResponse": {
"type": "object",
"properties": {
"match": {
"$ref": "#/definitions/openmatchMatch",
"description": "A Match generated by the user-defined MMF with the specified MatchProfiles.\nA valid Match response will contain at least one ticket."
}
}
},
"openmatchFunctionConfig": {
"type": "object",
"properties": {
"host": {
@ -188,12 +188,12 @@
"format": "int32"
},
"type": {
"$ref": "#/definitions/apiFunctionConfigType"
"$ref": "#/definitions/openmatchFunctionConfigType"
}
},
"description": "Configuration for the Match Function to be triggered by Open Match to\ngenerate proposals."
"title": "FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF"
},
"apiFunctionConfigType": {
"openmatchFunctionConfigType": {
"type": "string",
"enum": [
"GRPC",
@ -201,7 +201,7 @@
],
"default": "GRPC"
},
"apiMatch": {
"openmatchMatch": {
"type": "object",
"properties": {
"match_id": {
@ -219,69 +219,87 @@
"tickets": {
"type": "array",
"items": {
"$ref": "#/definitions/apiTicket"
"$ref": "#/definitions/openmatchTicket"
},
"description": "Tickets belonging to this match."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
"$ref": "#/definitions/openmatchRoster"
},
"title": "Set of Rosters that comprise this Match"
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Match properties for this Match. Open Match does not interpret this field."
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Match is used to represent a completed match object. It can be generated by\na MatchFunction as a proposal or can be returned by OpenMatch as a result in\nresponse to the FetchMatches call.\nWhen a match is returned by the FetchMatches call, it should contain at least \none ticket to be considered as valid."
},
"apiMatchProfile": {
"openmatchMatchProfile": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of this match profile."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Set of properties associated with this MatchProfile. (Optional)\nOpen Match does not interpret these properties but passes them through to\nthe MatchFunction."
},
"pools": {
"type": "array",
"items": {
"$ref": "#/definitions/apiPool"
"$ref": "#/definitions/openmatchPool"
},
"description": "Set of pools to be queried when generating a match for this MatchProfile.\nThe pool names can be used in empty Rosters to specify composition of a\nmatch."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
"$ref": "#/definitions/openmatchRoster"
},
"description": "Set of Rosters for this match request. Could be empty Rosters used to\nindicate the composition of the generated Match or they could be partially\npre-populated Ticket list to be used in scenarios such as backfill / join\nin progress."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A MatchProfile is Open Match's representation of a Match specification. It is\nused to indicate the criteria for selecting players for a match. A\nMatchProfile is the input to the API to get matches and is passed to the\nMatchFunction. It contains all the information required by the MatchFunction\nto generate match proposals."
},
"apiPool": {
"openmatchPool": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A developer-chosen human-readable name for this Pool."
},
"filters": {
"double_range_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiFilter"
"$ref": "#/definitions/openmatchDoubleRangeFilter"
},
"description": "Set of Filters indicating the filtering criteria. Selected players must\nmatch every Filter."
},
"string_equals_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchStringEqualsFilter"
}
},
"tag_present_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchTagPresentFilter"
}
}
}
},
"apiRoster": {
"openmatchRoster": {
"type": "object",
"properties": {
"name": {
@ -298,23 +316,80 @@
},
"description": "A Roster is a named collection of Ticket IDs. It exists so that a Tickets\nassociated with a Match can be labelled to belong to a team, sub-team etc. It\ncan also be used to represent the current state of a Match in scenarios such\nas backfill, join-in-progress etc."
},
"apiTicket": {
"openmatchSearchFields": {
"type": "object",
"properties": {
"double_args": {
"type": "object",
"additionalProperties": {
"type": "number",
"format": "double"
},
"description": "Float arguments. Filterable on ranges."
},
"string_args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "String arguments. Filterable on equality."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filterable on presence or absence of given value."
}
},
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"openmatchStringEqualsFilter": {
"type": "object",
"properties": {
"string_arg": {
"type": "string",
"description": "Name of the ticket's search_fields.string_args this Filter operates on."
},
"value": {
"type": "string"
}
},
"title": "Filters strings exactly equaling a value.\n string_arg: \"foo\"\n value: \"bar\"\nmatches:\n {\"foo\": \"bar\"}\ndoes not match:\n {\"foo\": \"baz\"}\n {\"bar\": \"foo\"}\n {}"
},
"openmatchTagPresentFilter": {
"type": "object",
"properties": {
"tag": {
"type": "string"
}
},
"title": "Filters to the tag being present on the search_fields.\n tag: \"foo\"\nmatches:\n [\"foo\"]\n [\"bar\",\"foo\"]\ndoes not match:\n [\"bar\"]\n []"
},
"openmatchTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
"description": "Id represents an auto-generated Id issued by Open Match."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment represents a game server assignment associated with a Ticket. \nOpen Match does not require or inspect any fields on Assignment."
},
"search_fields": {
"$ref": "#/definitions/openmatchSearchFields",
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
"description": "A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof SearchFields. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
@ -331,72 +406,6 @@
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
@ -419,6 +428,45 @@
},
"description": "- Simple to use and understand for most users\n- Flexible enough to meet unexpected needs\n\n# Overview\n\nThe `Status` message contains three pieces of data: error code, error\nmessage, and error details. The error code should be an enum value of\n[google.rpc.Code][google.rpc.Code], but it may accept additional error codes\nif needed. The error message should be a developer-facing English message\nthat helps developers *understand* and *resolve* the error. If a localized\nuser-facing error message is needed, put the localized message in the error\ndetails or localize it in the client. The optional error details may contain\narbitrary information about the error. There is a predefined set of error\ndetail types in the package `google.rpc` that can be used for common error\nconditions.\n\n# Language mapping\n\nThe `Status` message is the logical representation of the error model, but it\nis not necessarily the actual wire format. When the `Status` message is\nexposed in different client libraries and different wire protocols, it can be\nmapped differently. For example, it will likely be mapped to some exceptions\nin Java, but more likely mapped to some error codes in C.\n\n# Other uses\n\nThe error model and the `Status` message can be used in a variety of\nenvironments, either with or without APIs, to provide a\nconsistent developer experience across different environments.\n\nExample uses of this error model include:\n\n- Partial errors. If a service needs to return partial errors to the client,\n it may embed the `Status` in the normal response to indicate the partial\n errors.\n\n- Workflow errors. A typical workflow has multiple steps. Each step may\n have a `Status` message for error reporting.\n\n- Batch operations. If a client uses batch request and batch response, the\n `Status` message should be used directly inside batch response, one for\n each error sub-response.\n\n- Asynchronous operations. If an API call embeds asynchronous operation\n results in its response, the status of those operations should be\n represented directly using the `Status` message.\n\n- Logging. If some API errors are stored in logs, the message `Status` could\n be used directly after any stripping needed for security/privacy reasons.",
"title": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). The error model is designed to be:"
},
"runtimeStreamError": {
"type": "object",
"properties": {
"grpc_code": {
"type": "integer",
"format": "int32"
},
"http_code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"http_status": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
}
},
"x-stream-definitions": {
"openmatchFetchMatchesResponse": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/openmatchFetchMatchesResponse"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of openmatchFetchMatchesResponse"
}
},
"externalDocs": {

@ -13,8 +13,9 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "api/messages.proto";
import "google/api/annotations.proto";
@ -55,21 +56,19 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
};
message EvaluateRequest {
// List of Matches to evaluate.
repeated api.Match matches = 1;
// A Matches proposed by the Match Function representing a candidate of the final results.
Match match = 1;
}
message EvaluateResponse {
// Accepted list of Matches.
repeated api.Match matches = 1;
// A Match shortlisted by the evaluator representing one of the final results.
Match match = 1;
}
// The service implementing the Evaluator API that is called to evaluate
// matches generated by MMFs and shortlist them to accepted results.
// The Evaluator service implements APIs used to evaluate and shortlist matches proposed by MMFs.
service Evaluator {
// Evaluate accepts a list of proposed matches, evaluates them for quality,
// collisions etc. and returns matches that should be accepted as results.
rpc Evaluate(EvaluateRequest) returns (EvaluateResponse) {
// Evaluate evaluates a list of proposed matches based on quality, collision status, and etc, then shortlist the matches and returns the final results.
rpc Evaluate(stream EvaluateRequest) returns (stream EvaluateResponse) {
option (google.api.http) = {
post: "/v1/evaluator/matches:evaluate"
body: "*"

@ -26,13 +26,13 @@
"paths": {
"/v1/evaluator/matches:evaluate": {
"post": {
"summary": "Evaluate accepts a list of proposed matches, evaluates them for quality,\ncollisions etc. and returns matches that should be accepted as results.",
"summary": "Evaluate evaluates a list of proposed matches based on quality, collision status, and etc, then shortlist the matches and returns the final results.",
"operationId": "Evaluate",
"responses": {
"200": {
"description": "A successful response.",
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/definitions/apiEvaluateResponse"
"$ref": "#/x-stream-definitions/openmatchEvaluateResponse"
}
},
"404": {
@ -45,10 +45,11 @@
"parameters": [
{
"name": "body",
"description": " (streaming inputs)",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiEvaluateRequest"
"$ref": "#/definitions/openmatchEvaluateRequest"
}
}
],
@ -59,49 +60,46 @@
}
},
"definitions": {
"apiAssignment": {
"openmatchAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
"description": "An Assignment represents a game server assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiEvaluateRequest": {
"openmatchEvaluateRequest": {
"type": "object",
"properties": {
"matches": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "List of Matches to evaluate."
"match": {
"$ref": "#/definitions/openmatchMatch",
"description": "A Matches proposed by the Match Function representing a candidate of the final results."
}
}
},
"apiEvaluateResponse": {
"openmatchEvaluateResponse": {
"type": "object",
"properties": {
"matches": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "Accepted list of Matches."
"match": {
"$ref": "#/definitions/openmatchMatch",
"description": "A Match shortlisted by the evaluator representing one of the final results."
}
}
},
"apiMatch": {
"openmatchMatch": {
"type": "object",
"properties": {
"match_id": {
@ -119,25 +117,28 @@
"tickets": {
"type": "array",
"items": {
"$ref": "#/definitions/apiTicket"
"$ref": "#/definitions/openmatchTicket"
},
"description": "Tickets belonging to this match."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
"$ref": "#/definitions/openmatchRoster"
},
"title": "Set of Rosters that comprise this Match"
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Match properties for this Match. Open Match does not interpret this field."
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Match is used to represent a completed match object. It can be generated by\na MatchFunction as a proposal or can be returned by OpenMatch as a result in\nresponse to the FetchMatches call.\nWhen a match is returned by the FetchMatches call, it should contain at least \none ticket to be considered as valid."
},
"apiRoster": {
"openmatchRoster": {
"type": "object",
"properties": {
"name": {
@ -154,23 +155,58 @@
},
"description": "A Roster is a named collection of Ticket IDs. It exists so that a Tickets\nassociated with a Match can be labelled to belong to a team, sub-team etc. It\ncan also be used to represent the current state of a Match in scenarios such\nas backfill, join-in-progress etc."
},
"apiTicket": {
"openmatchSearchFields": {
"type": "object",
"properties": {
"double_args": {
"type": "object",
"additionalProperties": {
"type": "number",
"format": "double"
},
"description": "Float arguments. Filterable on ranges."
},
"string_args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "String arguments. Filterable on equality."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filterable on presence or absence of given value."
}
},
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"openmatchTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
"description": "Id represents an auto-generated Id issued by Open Match."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment represents a game server assignment associated with a Ticket. \nOpen Match does not require or inspect any fields on Assignment."
},
"search_fields": {
"$ref": "#/definitions/openmatchSearchFields",
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
"description": "A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof SearchFields. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
@ -187,72 +223,6 @@
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
@ -275,6 +245,45 @@
},
"description": "- Simple to use and understand for most users\n- Flexible enough to meet unexpected needs\n\n# Overview\n\nThe `Status` message contains three pieces of data: error code, error\nmessage, and error details. The error code should be an enum value of\n[google.rpc.Code][google.rpc.Code], but it may accept additional error codes\nif needed. The error message should be a developer-facing English message\nthat helps developers *understand* and *resolve* the error. If a localized\nuser-facing error message is needed, put the localized message in the error\ndetails or localize it in the client. The optional error details may contain\narbitrary information about the error. There is a predefined set of error\ndetail types in the package `google.rpc` that can be used for common error\nconditions.\n\n# Language mapping\n\nThe `Status` message is the logical representation of the error model, but it\nis not necessarily the actual wire format. When the `Status` message is\nexposed in different client libraries and different wire protocols, it can be\nmapped differently. For example, it will likely be mapped to some exceptions\nin Java, but more likely mapped to some error codes in C.\n\n# Other uses\n\nThe error model and the `Status` message can be used in a variety of\nenvironments, either with or without APIs, to provide a\nconsistent developer experience across different environments.\n\nExample uses of this error model include:\n\n- Partial errors. If a service needs to return partial errors to the client,\n it may embed the `Status` in the normal response to indicate the partial\n errors.\n\n- Workflow errors. A typical workflow has multiple steps. Each step may\n have a `Status` message for error reporting.\n\n- Batch operations. If a client uses batch request and batch response, the\n `Status` message should be used directly inside batch response, one for\n each error sub-response.\n\n- Asynchronous operations. If an API call embeds asynchronous operation\n results in its response, the status of those operations should be\n represented directly using the `Status` message.\n\n- Logging. If some API errors are stored in logs, the message `Status` could\n be used directly after any stripping needed for security/privacy reasons.",
"title": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). The error model is designed to be:"
},
"runtimeStreamError": {
"type": "object",
"properties": {
"grpc_code": {
"type": "integer",
"format": "int32"
},
"http_code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"http_status": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
}
},
"x-stream-definitions": {
"openmatchEvaluateResponse": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/openmatchEvaluateResponse"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of openmatchEvaluateResponse"
}
},
"externalDocs": {

24
api/extensions.proto Normal file

@ -0,0 +1,24 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
// A DefaultEvaluationCriteria is used for a match's evaluation_input when using
// the default evaluator.
message DefaultEvaluationCriteria {
double score = 1;
}

@ -13,8 +13,9 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "api/messages.proto";
import "google/api/annotations.proto";
@ -55,45 +56,43 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
};
message CreateTicketRequest {
// Ticket object with the properties of the Ticket to be created.
// A Ticket object with SearchFields defined.
Ticket ticket = 1;
}
message CreateTicketResponse {
// Ticket object for the created Ticket - with the ticket ID populated.
// A Ticket object with TicketId generated.
Ticket ticket = 1;
}
message DeleteTicketRequest {
// Ticket ID of the Ticket to be deleted.
// A TicketId of a generated Ticket to be deleted.
string ticket_id = 1;
}
message DeleteTicketResponse {}
message GetTicketRequest {
// Ticket ID of the Ticket to fetch.
// A TicketId of a generated Ticket.
string ticket_id = 1;
}
message GetAssignmentsRequest {
// Ticket ID of the Ticket to get updates on.
// A TicketId of a generated Ticket to get updates on.
string ticket_id = 1;
}
message GetAssignmentsResponse {
// The updated Ticket object.
// An updated Assignment of the requested Ticket.
Assignment assignment = 1;
}
// The Frontend service enables creating Tickets for matchmaking and fetching
// the status of these Tickets.
// The Frontend service implements APIs to manage and query status of a Tickets.
service Frontend {
// CreateTicket will create a new ticket, assign a Ticket ID to it and put the
// Ticket in state storage. It will then look through the 'properties' field
// for the attributes defined as indices the matchmakaking config. If the
// attributes exist and are valid integers, they will be indexed. Creating a
// ticket adds the Ticket to the pool of Tickets considered for matchmaking.
// CreateTicket assigns an unique TicketId to the input Ticket and record it in state storage.
// A ticket is considered as ready for matchmaking once it is created.
// - If a TicketId exists in a Ticket request, an auto-generated TicketId will override this field.
// - If SearchFields exist in a Ticket, CreateTicket will also index these fields such that one can query the ticket with mmlogic.QueryTickets function.
rpc CreateTicket(CreateTicketRequest) returns (CreateTicketResponse) {
option (google.api.http) = {
post: "/v1/frontend/tickets"
@ -101,26 +100,25 @@ service Frontend {
};
}
// DeleteTicket removes the Ticket from state storage and from corresponding
// configured indices and lazily removes the ticket from state storage.
// Deleting a ticket immediately stops the ticket from being
// considered for future matchmaking requests, yet when the ticket itself will be deleted
// is undeterministic. Users may still be able to assign/get a ticket after calling DeleteTicket on it.
// DeleteTicket immediately stops Open Match from using the Ticket for matchmaking and removes the Ticket from state storage.
// The client must delete the Ticket when finished matchmaking with it.
// - If SearchFields exist in a Ticket, DeleteTicket will deindex the fields lazily.
// Users may still be able to assign/get a ticket after calling DeleteTicket on it.
rpc DeleteTicket(DeleteTicketRequest) returns (DeleteTicketResponse) {
option (google.api.http) = {
delete: "/v1/frontend/tickets/{ticket_id}"
};
}
// GetTicket fetches the ticket associated with the specified Ticket ID.
// GetTicket get the Ticket associated with the specified TicketId.
rpc GetTicket(GetTicketRequest) returns (Ticket) {
option (google.api.http) = {
get: "/v1/frontend/tickets/{ticket_id}"
};
}
// GetAssignments streams matchmaking results from Open Match for the
// provided Ticket ID.
// GetAssignments stream back Assignment of the specified TicketId if it is updated.
// - If the Assignment is not updated, GetAssignment will retry using the configured backoff strategy.
rpc GetAssignments(GetAssignmentsRequest)
returns (stream GetAssignmentsResponse) {
option (google.api.http) = {

@ -26,13 +26,13 @@
"paths": {
"/v1/frontend/tickets": {
"post": {
"summary": "CreateTicket will create a new ticket, assign a Ticket ID to it and put the\nTicket in state storage. It will then look through the 'properties' field\nfor the attributes defined as indices the matchmakaking config. If the\nattributes exist and are valid integers, they will be indexed. Creating a\nticket adds the Ticket to the pool of Tickets considered for matchmaking.",
"summary": "CreateTicket assigns an unique TicketId to the input Ticket and record it in state storage.\nA ticket is considered as ready for matchmaking once it is created.\n - If a TicketId exists in a Ticket request, an auto-generated TicketId will override this field.\n - If SearchFields exist in a Ticket, CreateTicket will also index these fields such that one can query the ticket with mmlogic.QueryTickets function.",
"operationId": "CreateTicket",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiCreateTicketResponse"
"$ref": "#/definitions/openmatchCreateTicketResponse"
}
},
"404": {
@ -48,7 +48,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiCreateTicketRequest"
"$ref": "#/definitions/openmatchCreateTicketRequest"
}
}
],
@ -59,13 +59,13 @@
},
"/v1/frontend/tickets/{ticket_id}": {
"get": {
"summary": "GetTicket fetches the ticket associated with the specified Ticket ID.",
"summary": "GetTicket get the Ticket associated with the specified TicketId.",
"operationId": "GetTicket",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiTicket"
"$ref": "#/definitions/openmatchTicket"
}
},
"404": {
@ -78,7 +78,7 @@
"parameters": [
{
"name": "ticket_id",
"description": "Ticket ID of the Ticket to fetch.",
"description": "A TicketId of a generated Ticket.",
"in": "path",
"required": true,
"type": "string"
@ -89,13 +89,13 @@
]
},
"delete": {
"summary": "DeleteTicket removes the Ticket from state storage and from corresponding\nconfigured indices and lazily removes the ticket from state storage.\nDeleting a ticket immediately stops the ticket from being\nconsidered for future matchmaking requests, yet when the ticket itself will be deleted\nis undeterministic. Users may still be able to assign/get a ticket after calling DeleteTicket on it.",
"summary": "DeleteTicket immediately stops Open Match from using the Ticket for matchmaking and removes the Ticket from state storage.\nThe client must delete the Ticket when finished matchmaking with it. \n - If SearchFields exist in a Ticket, DeleteTicket will deindex the fields lazily.\nUsers may still be able to assign/get a ticket after calling DeleteTicket on it.",
"operationId": "DeleteTicket",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiDeleteTicketResponse"
"$ref": "#/definitions/openmatchDeleteTicketResponse"
}
},
"404": {
@ -108,7 +108,7 @@
"parameters": [
{
"name": "ticket_id",
"description": "Ticket ID of the Ticket to be deleted.",
"description": "A TicketId of a generated Ticket to be deleted.",
"in": "path",
"required": true,
"type": "string"
@ -121,13 +121,13 @@
},
"/v1/frontend/tickets/{ticket_id}/assignments": {
"get": {
"summary": "GetAssignments streams matchmaking results from Open Match for the\nprovided Ticket ID.",
"summary": "GetAssignments stream back Assignment of the specified TicketId if it is updated.\n - If the Assignment is not updated, GetAssignment will retry using the configured backoff strategy.",
"operationId": "GetAssignments",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/x-stream-definitions/apiGetAssignmentsResponse"
"$ref": "#/x-stream-definitions/openmatchGetAssignmentsResponse"
}
},
"404": {
@ -140,7 +140,7 @@
"parameters": [
{
"name": "ticket_id",
"description": "Ticket ID of the Ticket to get updates on.",
"description": "A TicketId of a generated Ticket to get updates on.",
"in": "path",
"required": true,
"type": "string"
@ -153,71 +153,109 @@
}
},
"definitions": {
"apiAssignment": {
"openmatchAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
"description": "An Assignment represents a game server assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiCreateTicketRequest": {
"openmatchCreateTicketRequest": {
"type": "object",
"properties": {
"ticket": {
"$ref": "#/definitions/apiTicket",
"description": "Ticket object with the properties of the Ticket to be created."
"$ref": "#/definitions/openmatchTicket",
"description": "A Ticket object with SearchFields defined."
}
}
},
"apiCreateTicketResponse": {
"openmatchCreateTicketResponse": {
"type": "object",
"properties": {
"ticket": {
"$ref": "#/definitions/apiTicket",
"description": "Ticket object for the created Ticket - with the ticket ID populated."
"$ref": "#/definitions/openmatchTicket",
"description": "A Ticket object with TicketId generated."
}
}
},
"apiDeleteTicketResponse": {
"openmatchDeleteTicketResponse": {
"type": "object"
},
"apiGetAssignmentsResponse": {
"openmatchGetAssignmentsResponse": {
"type": "object",
"properties": {
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "The updated Ticket object."
"$ref": "#/definitions/openmatchAssignment",
"description": "An updated Assignment of the requested Ticket."
}
}
},
"apiTicket": {
"openmatchSearchFields": {
"type": "object",
"properties": {
"double_args": {
"type": "object",
"additionalProperties": {
"type": "number",
"format": "double"
},
"description": "Float arguments. Filterable on ranges."
},
"string_args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "String arguments. Filterable on equality."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filterable on presence or absence of given value."
}
},
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"openmatchTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
"description": "Id represents an auto-generated Id issued by Open Match."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment represents a game server assignment associated with a Ticket. \nOpen Match does not require or inspect any fields on Assignment."
},
"search_fields": {
"$ref": "#/definitions/openmatchSearchFields",
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
"description": "A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof SearchFields. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
@ -234,72 +272,6 @@
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
@ -350,17 +322,17 @@
}
},
"x-stream-definitions": {
"apiGetAssignmentsResponse": {
"openmatchGetAssignmentsResponse": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/apiGetAssignmentsResponse"
"$ref": "#/definitions/openmatchGetAssignmentsResponse"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of apiGetAssignmentsResponse"
"title": "Stream result of openmatchGetAssignmentsResponse"
}
},
"externalDocs": {

@ -13,8 +13,9 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "api/messages.proto";
import "google/api/annotations.proto";
@ -55,23 +56,22 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
};
message RunRequest {
// The MatchProfile that describes the Match that this MatchFunction needs to
// generate proposals for.
// A MatchProfile defines constraints of Tickets in a Match and shapes the Match proposed by the MatchFunction.
MatchProfile profile = 1;
}
message RunResponse {
// The proposal generated by this MatchFunction Run.
// Note that OpenMatch will validate the proposals, a valid match should contain at least one ticket.
repeated Match proposals = 1;
// A Proposal represents a Match candidate that satifies the constraints defined in the input Profile.
// A valid Proposal response will contain at least one ticket.
Match proposal = 1;
}
// This proto defines the API for running Match Functions as long-lived,
// 'serving' functions.
// The MatchFunction service implements APIs to run user-defined matchmaking logics.
service MatchFunction {
// This is the function that is executed when by the Open Match backend to
// generate Match proposals.
rpc Run(RunRequest) returns (RunResponse) {
// DO NOT CALL THIS FUNCTION MANUALLY. USE backend.FetchMatches INSTEAD.
// Run pulls Tickets that satisify Profile constraints from Mmlogic, runs matchmaking logics against them, then
// constructs and streams back match candidates to the Backend service.
rpc Run(RunRequest) returns (stream RunResponse) {
option (google.api.http) = {
post: "/v1/matchfunction:run"
body: "*"

@ -26,13 +26,13 @@
"paths": {
"/v1/matchfunction:run": {
"post": {
"summary": "This is the function that is executed when by the Open Match backend to\ngenerate Match proposals.",
"summary": "DO NOT CALL THIS FUNCTION MANUALLY. USE backend.FetchMatches INSTEAD.\nRun pulls Tickets that satisify Profile constraints from Mmlogic, runs matchmaking logics against them, then\nconstructs and streams back match candidates to the Backend service.",
"operationId": "Run",
"responses": {
"200": {
"description": "A successful response.",
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/definitions/apiRunResponse"
"$ref": "#/x-stream-definitions/openmatchRunResponse"
}
},
"404": {
@ -48,7 +48,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiRunRequest"
"$ref": "#/definitions/openmatchRunRequest"
}
}
],
@ -59,30 +59,33 @@
}
},
"definitions": {
"apiAssignment": {
"openmatchAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
"description": "An Assignment represents a game server assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiFilter": {
"openmatchDoubleRangeFilter": {
"type": "object",
"properties": {
"attribute": {
"double_arg": {
"type": "string",
"description": "Name of the ticket attribute this Filter operates on."
"description": "Name of the ticket's search_fields.double_args this Filter operates on."
},
"max": {
"type": "number",
@ -95,9 +98,9 @@
"description": "Minimum value. Defaults to 0."
}
},
"description": "A hard filter used to query a subset of Tickets meeting the filtering\ncriteria."
"title": "Filters numerical values to only those within a range.\n double_arg: \"foo\"\n max: 10\n min: 5\nmatches:\n {\"foo\": 5}\n {\"foo\": 7.5}\n {\"foo\": 10}\ndoes not match:\n {\"foo\": 4}\n {\"foo\": 10.01}\n {\"foo\": \"7.5\"}\n {}"
},
"apiMatch": {
"openmatchMatch": {
"type": "object",
"properties": {
"match_id": {
@ -115,69 +118,87 @@
"tickets": {
"type": "array",
"items": {
"$ref": "#/definitions/apiTicket"
"$ref": "#/definitions/openmatchTicket"
},
"description": "Tickets belonging to this match."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
"$ref": "#/definitions/openmatchRoster"
},
"title": "Set of Rosters that comprise this Match"
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Match properties for this Match. Open Match does not interpret this field."
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Match is used to represent a completed match object. It can be generated by\na MatchFunction as a proposal or can be returned by OpenMatch as a result in\nresponse to the FetchMatches call.\nWhen a match is returned by the FetchMatches call, it should contain at least \none ticket to be considered as valid."
},
"apiMatchProfile": {
"openmatchMatchProfile": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of this match profile."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Set of properties associated with this MatchProfile. (Optional)\nOpen Match does not interpret these properties but passes them through to\nthe MatchFunction."
},
"pools": {
"type": "array",
"items": {
"$ref": "#/definitions/apiPool"
"$ref": "#/definitions/openmatchPool"
},
"description": "Set of pools to be queried when generating a match for this MatchProfile.\nThe pool names can be used in empty Rosters to specify composition of a\nmatch."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
"$ref": "#/definitions/openmatchRoster"
},
"description": "Set of Rosters for this match request. Could be empty Rosters used to\nindicate the composition of the generated Match or they could be partially\npre-populated Ticket list to be used in scenarios such as backfill / join\nin progress."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A MatchProfile is Open Match's representation of a Match specification. It is\nused to indicate the criteria for selecting players for a match. A\nMatchProfile is the input to the API to get matches and is passed to the\nMatchFunction. It contains all the information required by the MatchFunction\nto generate match proposals."
},
"apiPool": {
"openmatchPool": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A developer-chosen human-readable name for this Pool."
},
"filters": {
"double_range_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiFilter"
"$ref": "#/definitions/openmatchDoubleRangeFilter"
},
"description": "Set of Filters indicating the filtering criteria. Selected players must\nmatch every Filter."
},
"string_equals_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchStringEqualsFilter"
}
},
"tag_present_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchTagPresentFilter"
}
}
}
},
"apiRoster": {
"openmatchRoster": {
"type": "object",
"properties": {
"name": {
@ -194,44 +215,98 @@
},
"description": "A Roster is a named collection of Ticket IDs. It exists so that a Tickets\nassociated with a Match can be labelled to belong to a team, sub-team etc. It\ncan also be used to represent the current state of a Match in scenarios such\nas backfill, join-in-progress etc."
},
"apiRunRequest": {
"openmatchRunRequest": {
"type": "object",
"properties": {
"profile": {
"$ref": "#/definitions/apiMatchProfile",
"description": "The MatchProfile that describes the Match that this MatchFunction needs to\ngenerate proposals for."
"$ref": "#/definitions/openmatchMatchProfile",
"description": "A MatchProfile defines constraints of Tickets in a Match and shapes the Match proposed by the MatchFunction."
}
}
},
"apiRunResponse": {
"openmatchRunResponse": {
"type": "object",
"properties": {
"proposals": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "The proposal generated by this MatchFunction Run.\nNote that OpenMatch will validate the proposals, a valid match should contain at least one ticket."
"proposal": {
"$ref": "#/definitions/openmatchMatch",
"description": "A Proposal represents a Match candidate that satifies the constraints defined in the input Profile.\nA valid Proposal response will contain at least one ticket."
}
}
},
"apiTicket": {
"openmatchSearchFields": {
"type": "object",
"properties": {
"double_args": {
"type": "object",
"additionalProperties": {
"type": "number",
"format": "double"
},
"description": "Float arguments. Filterable on ranges."
},
"string_args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "String arguments. Filterable on equality."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filterable on presence or absence of given value."
}
},
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"openmatchStringEqualsFilter": {
"type": "object",
"properties": {
"string_arg": {
"type": "string",
"description": "Name of the ticket's search_fields.string_args this Filter operates on."
},
"value": {
"type": "string"
}
},
"title": "Filters strings exactly equaling a value.\n string_arg: \"foo\"\n value: \"bar\"\nmatches:\n {\"foo\": \"bar\"}\ndoes not match:\n {\"foo\": \"baz\"}\n {\"bar\": \"foo\"}\n {}"
},
"openmatchTagPresentFilter": {
"type": "object",
"properties": {
"tag": {
"type": "string"
}
},
"title": "Filters to the tag being present on the search_fields.\n tag: \"foo\"\nmatches:\n [\"foo\"]\n [\"bar\",\"foo\"]\ndoes not match:\n [\"bar\"]\n []"
},
"openmatchTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
"description": "Id represents an auto-generated Id issued by Open Match."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment represents a game server assignment associated with a Ticket. \nOpen Match does not require or inspect any fields on Assignment."
},
"search_fields": {
"$ref": "#/definitions/openmatchSearchFields",
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
"description": "A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof SearchFields. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
@ -248,72 +323,6 @@
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
@ -336,6 +345,45 @@
},
"description": "- Simple to use and understand for most users\n- Flexible enough to meet unexpected needs\n\n# Overview\n\nThe `Status` message contains three pieces of data: error code, error\nmessage, and error details. The error code should be an enum value of\n[google.rpc.Code][google.rpc.Code], but it may accept additional error codes\nif needed. The error message should be a developer-facing English message\nthat helps developers *understand* and *resolve* the error. If a localized\nuser-facing error message is needed, put the localized message in the error\ndetails or localize it in the client. The optional error details may contain\narbitrary information about the error. There is a predefined set of error\ndetail types in the package `google.rpc` that can be used for common error\nconditions.\n\n# Language mapping\n\nThe `Status` message is the logical representation of the error model, but it\nis not necessarily the actual wire format. When the `Status` message is\nexposed in different client libraries and different wire protocols, it can be\nmapped differently. For example, it will likely be mapped to some exceptions\nin Java, but more likely mapped to some error codes in C.\n\n# Other uses\n\nThe error model and the `Status` message can be used in a variety of\nenvironments, either with or without APIs, to provide a\nconsistent developer experience across different environments.\n\nExample uses of this error model include:\n\n- Partial errors. If a service needs to return partial errors to the client,\n it may embed the `Status` in the normal response to indicate the partial\n errors.\n\n- Workflow errors. A typical workflow has multiple steps. Each step may\n have a `Status` message for error reporting.\n\n- Batch operations. If a client uses batch request and batch response, the\n `Status` message should be used directly inside batch response, one for\n each error sub-response.\n\n- Asynchronous operations. If an API call embeds asynchronous operation\n results in its response, the status of those operations should be\n represented directly using the `Status` message.\n\n- Logging. If some API errors are stored in logs, the message `Status` could\n be used directly after any stripping needed for security/privacy reasons.",
"title": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). The error model is designed to be:"
},
"runtimeStreamError": {
"type": "object",
"properties": {
"grpc_code": {
"type": "integer",
"format": "int32"
},
"http_code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"http_status": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
}
},
"x-stream-definitions": {
"openmatchRunResponse": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/openmatchRunResponse"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of openmatchRunResponse"
}
},
"externalDocs": {

@ -13,50 +13,86 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "google/rpc/status.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/any.proto";
// A Ticket is a basic matchmaking entity in Open Match. In order to enter
// matchmaking using Open Match, the client should generate a Ticket, passing in
// the properties to be associated with this Ticket. Open Match will generate an
// ID for a Ticket during creation. A Ticket could be used to represent an
// A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an
// individual 'Player' or a 'Group' of players. Open Match will not interpret
// what the Ticket represents but just treat it as a matchmaking unit with a set
// of properties. Open Match stores the Ticket in state storage and enables an
// of SearchFields. Open Match stores the Ticket in state storage and enables an
// Assignment to be associated with this Ticket.
message Ticket {
// The Ticket ID generated by Open Match.
// Id represents an auto-generated Id issued by Open Match.
string id = 1;
// Properties contains custom info about the ticket. Top level values can be
// used in indexing and filtering to find tickets.
google.protobuf.Struct properties = 2;
// Assignment associated with the Ticket.
// An Assignment represents a game server assignment associated with a Ticket.
// Open Match does not require or inspect any fields on Assignment.
Assignment assignment = 3;
// Search fields are the fields which Open Match is aware of, and can be used
// when specifying filters.
SearchFields search_fields = 4;
// Customized information not inspected by Open Match, to be used by the match
// making function, evaluator, and components making calls to Open Match.
// Optional, depending on the requirements of the connected systems.
map<string, google.protobuf.Any> extensions = 5;
// Deprecated fields.
reserved 2;
}
// An Assignment object represents the assignment associated with a Ticket. Open
// Search fields are the fields which Open Match is aware of, and can be used
// when specifying filters.
message SearchFields {
// Float arguments. Filterable on ranges.
map<string, double> double_args = 1;
// String arguments. Filterable on equality.
map<string, string> string_args = 2;
// Filterable on presence or absence of given value.
repeated string tags = 3;
}
// An Assignment represents a game server assignment associated with a Ticket. Open
// match does not require or inspect any fields on assignment.
message Assignment {
// Connection information for this Assignment.
string connection = 1;
// Other details to be sent to the players.
google.protobuf.Struct properties = 2;
// Error when finding an Assignment for this Ticket.
google.rpc.Status error = 3;
// Customized information not inspected by Open Match, to be used by the match
// making function, evaluator, and components making calls to Open Match.
// Optional, depending on the requirements of the connected systems.
map<string, google.protobuf.Any> extensions = 4;
// Deprecated fields.
reserved 2;
}
// A hard filter used to query a subset of Tickets meeting the filtering
// criteria.
message Filter {
// Name of the ticket attribute this Filter operates on.
string attribute = 1;
// Filters numerical values to only those within a range.
// double_arg: "foo"
// max: 10
// min: 5
// matches:
// {"foo": 5}
// {"foo": 7.5}
// {"foo": 10}
// does not match:
// {"foo": 4}
// {"foo": 10.01}
// {"foo": "7.5"}
// {}
message DoubleRangeFilter {
// Name of the ticket's search_fields.double_args this Filter operates on.
string double_arg = 1;
// Maximum value. Defaults to positive infinity (any value above minv).
double max = 2;
@ -65,13 +101,48 @@ message Filter {
double min = 3;
}
// Filters strings exactly equaling a value.
// string_arg: "foo"
// value: "bar"
// matches:
// {"foo": "bar"}
// does not match:
// {"foo": "baz"}
// {"bar": "foo"}
// {}
message StringEqualsFilter {
// Name of the ticket's search_fields.string_args this Filter operates on.
string string_arg = 1;
string value = 2;
}
// Filters to the tag being present on the search_fields.
// tag: "foo"
// matches:
// ["foo"]
// ["bar","foo"]
// does not match:
// ["bar"]
// []
message TagPresentFilter {
string tag = 1;
}
message Pool {
// A developer-chosen human-readable name for this Pool.
string name = 1;
// Set of Filters indicating the filtering criteria. Selected players must
// match every Filter.
repeated Filter filters = 2;
repeated DoubleRangeFilter double_range_filters = 2;
repeated StringEqualsFilter string_equals_filters = 4;
repeated TagPresentFilter tag_present_filters = 5;
// Deprecated fields.
reserved 3;
}
// A Roster is a named collection of Ticket IDs. It exists so that a Tickets
@ -95,11 +166,6 @@ message MatchProfile {
// Name of this match profile.
string name = 1;
// Set of properties associated with this MatchProfile. (Optional)
// Open Match does not interpret these properties but passes them through to
// the MatchFunction.
google.protobuf.Struct properties = 2;
// Set of pools to be queried when generating a match for this MatchProfile.
// The pool names can be used in empty Rosters to specify composition of a
// match.
@ -110,6 +176,14 @@ message MatchProfile {
// pre-populated Ticket list to be used in scenarios such as backfill / join
// in progress.
repeated Roster rosters = 4;
// Customized information not inspected by Open Match, to be used by the match
// making function, evaluator, and components making calls to Open Match.
// Optional, depending on the requirements of the connected systems.
map<string, google.protobuf.Any> extensions = 5;
// Deprecated fields.
reserved 2;
}
// A Match is used to represent a completed match object. It can be generated by
@ -133,6 +207,11 @@ message Match {
// Set of Rosters that comprise this Match
repeated Roster rosters = 5;
// Match properties for this Match. Open Match does not interpret this field.
google.protobuf.Struct properties = 6;
// Customized information not inspected by Open Match, to be used by the match
// making function, evaluator, and components making calls to Open Match.
// Optional, depending on the requirements of the connected systems.
map<string, google.protobuf.Any> extensions = 7;
// Deprecated fields.
reserved 6;
}

@ -13,8 +13,9 @@
// limitations under the License.
syntax = "proto3";
package api;
option go_package = "pkg/pb";
package openmatch;
option go_package = "open-match.dev/open-match/pkg/pb";
option csharp_namespace = "OpenMatch";
import "api/messages.proto";
import "google/api/annotations.proto";
@ -55,20 +56,21 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
};
message QueryTicketsRequest {
// The Pool representing the set of Filters to be queried.
// A Pool is consists of a set of Filters.
Pool pool = 1;
}
message QueryTicketsResponse {
// The Tickets that meet the Filter criteria requested by the Pool.
// Tickets is a list of Ticket representing one or more Tickets which meet all Filter criterias.
repeated Ticket tickets = 1;
}
// The MMLogic API provides utility functions for common MMF functionality such
// as retreiving Tickets from state storage.
// The MmLogic service implements helper APIs for Match Function to query Tickets from state storage.
service MmLogic {
// QueryTickets gets the list of Tickets that match every Filter in the
// specified Pool.
// QueryTickets gets a list of Tickets that match all Filters of the input Pool.
// - If the Pool contains no Filters, QueryTickets will return all Tickets in the state storage.
// QueryTickets pages the Tickets by `storage.pool.size` and stream back response.
// - storage.pool.size is default to 1000 if not set, and has a mininum of 10 and maximum of 10000
rpc QueryTickets(QueryTicketsRequest) returns (stream QueryTicketsResponse) {
option (google.api.http) = {
post: "/v1/mmlogic/tickets:query"

@ -26,13 +26,13 @@
"paths": {
"/v1/mmlogic/tickets:query": {
"post": {
"summary": "QueryTickets gets the list of Tickets that match every Filter in the\nspecified Pool.",
"summary": "QueryTickets gets a list of Tickets that match all Filters of the input Pool.\n - If the Pool contains no Filters, QueryTickets will return all Tickets in the state storage.\nQueryTickets pages the Tickets by `storage.pool.size` and stream back response.\n - storage.pool.size is default to 1000 if not set, and has a mininum of 10 and maximum of 10000",
"operationId": "QueryTickets",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/x-stream-definitions/apiQueryTicketsResponse"
"$ref": "#/x-stream-definitions/openmatchQueryTicketsResponse"
}
},
"404": {
@ -48,7 +48,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiQueryTicketsRequest"
"$ref": "#/definitions/openmatchQueryTicketsRequest"
}
}
],
@ -59,30 +59,33 @@
}
},
"definitions": {
"apiAssignment": {
"openmatchAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
"description": "An Assignment represents a game server assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiFilter": {
"openmatchDoubleRangeFilter": {
"type": "object",
"properties": {
"attribute": {
"double_arg": {
"type": "string",
"description": "Name of the ticket attribute this Filter operates on."
"description": "Name of the ticket's search_fields.double_args this Filter operates on."
},
"max": {
"type": "number",
@ -95,62 +98,131 @@
"description": "Minimum value. Defaults to 0."
}
},
"description": "A hard filter used to query a subset of Tickets meeting the filtering\ncriteria."
"title": "Filters numerical values to only those within a range.\n double_arg: \"foo\"\n max: 10\n min: 5\nmatches:\n {\"foo\": 5}\n {\"foo\": 7.5}\n {\"foo\": 10}\ndoes not match:\n {\"foo\": 4}\n {\"foo\": 10.01}\n {\"foo\": \"7.5\"}\n {}"
},
"apiPool": {
"openmatchPool": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A developer-chosen human-readable name for this Pool."
},
"filters": {
"double_range_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiFilter"
"$ref": "#/definitions/openmatchDoubleRangeFilter"
},
"description": "Set of Filters indicating the filtering criteria. Selected players must\nmatch every Filter."
},
"string_equals_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchStringEqualsFilter"
}
},
"tag_present_filters": {
"type": "array",
"items": {
"$ref": "#/definitions/openmatchTagPresentFilter"
}
}
}
},
"apiQueryTicketsRequest": {
"openmatchQueryTicketsRequest": {
"type": "object",
"properties": {
"pool": {
"$ref": "#/definitions/apiPool",
"description": "The Pool representing the set of Filters to be queried."
"$ref": "#/definitions/openmatchPool",
"description": "A Pool is consists of a set of Filters."
}
}
},
"apiQueryTicketsResponse": {
"openmatchQueryTicketsResponse": {
"type": "object",
"properties": {
"tickets": {
"type": "array",
"items": {
"$ref": "#/definitions/apiTicket"
"$ref": "#/definitions/openmatchTicket"
},
"description": "The Tickets that meet the Filter criteria requested by the Pool."
"description": "Tickets is a list of Ticket representing one or more Tickets which meet all Filter criterias."
}
}
},
"apiTicket": {
"openmatchSearchFields": {
"type": "object",
"properties": {
"double_args": {
"type": "object",
"additionalProperties": {
"type": "number",
"format": "double"
},
"description": "Float arguments. Filterable on ranges."
},
"string_args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "String arguments. Filterable on equality."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filterable on presence or absence of given value."
}
},
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"openmatchStringEqualsFilter": {
"type": "object",
"properties": {
"string_arg": {
"type": "string",
"description": "Name of the ticket's search_fields.string_args this Filter operates on."
},
"value": {
"type": "string"
}
},
"title": "Filters strings exactly equaling a value.\n string_arg: \"foo\"\n value: \"bar\"\nmatches:\n {\"foo\": \"bar\"}\ndoes not match:\n {\"foo\": \"baz\"}\n {\"bar\": \"foo\"}\n {}"
},
"openmatchTagPresentFilter": {
"type": "object",
"properties": {
"tag": {
"type": "string"
}
},
"title": "Filters to the tag being present on the search_fields.\n tag: \"foo\"\nmatches:\n [\"foo\"]\n [\"bar\",\"foo\"]\ndoes not match:\n [\"bar\"]\n []"
},
"openmatchTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
"description": "Id represents an auto-generated Id issued by Open Match."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
"$ref": "#/definitions/openmatchAssignment",
"description": "An Assignment represents a game server assignment associated with a Ticket. \nOpen Match does not require or inspect any fields on Assignment."
},
"search_fields": {
"$ref": "#/definitions/openmatchSearchFields",
"description": "Search fields are the fields which Open Match is aware of, and can be used\nwhen specifying filters."
},
"extensions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufAny"
},
"description": "Customized information not inspected by Open Match, to be used by the match\nmaking function, evaluator, and components making calls to Open Match.\nOptional, depending on the requirements of the connected systems."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
"description": "A Ticket is a basic matchmaking entity in Open Match. A Ticket represents either an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof SearchFields. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
@ -167,72 +239,6 @@
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
@ -283,17 +289,17 @@
}
},
"x-stream-definitions": {
"apiQueryTicketsResponse": {
"openmatchQueryTicketsResponse": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/apiQueryTicketsResponse"
"$ref": "#/definitions/openmatchQueryTicketsResponse"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of apiQueryTicketsResponse"
"title": "Stream result of openmatchQueryTicketsResponse"
}
},
"externalDocs": {

@ -1,320 +0,0 @@
{
"swagger": "2.0",
"info": {
"title": "Synchronizer",
"version": "1.0",
"contact": {
"name": "Open Match",
"url": "https://open-match.dev",
"email": "open-match-discuss@googlegroups.com"
},
"license": {
"name": "Apache 2.0 License",
"url": "https://github.com/googleforgames/open-match/blob/master/LICENSE"
}
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v1/synchronizer/proposals:evaluate": {
"post": {
"summary": "EvaluateProposals accepts a list of proposals and a registration identifier\nfor this request. If the synchronization cycle to which the request was\nregistered is completed, this request fails otherwise the proposals are\nadded to the list of proposals to be evaluated in the current cycle. At the\n end of the cycle, the user defined evaluation method is triggered and the\nmatches accepted by it are returned as results.",
"operationId": "EvaluateProposals",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiEvaluateProposalsResponse"
}
},
"404": {
"description": "Returned when the resource does not exist.",
"schema": {
"format": "string"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/apiEvaluateProposalsRequest"
}
}
],
"tags": [
"Synchronizer"
]
}
},
"/v1/synchronizer/register": {
"get": {
"summary": "Register associates this request with the current synchronization cycle and\nreturns an identifier for this registration. The caller returns this\nidentifier back in the evaluation request. This enables synchronizer to\nidentify stale evaluation requests belonging to a prior window.",
"operationId": "Register",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/apiRegisterResponse"
}
},
"404": {
"description": "Returned when the resource does not exist.",
"schema": {
"format": "string"
}
}
},
"tags": [
"Synchronizer"
]
}
}
},
"definitions": {
"apiAssignment": {
"type": "object",
"properties": {
"connection": {
"type": "string",
"description": "Connection information for this Assignment."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Other details to be sent to the players."
},
"error": {
"$ref": "#/definitions/rpcStatus",
"description": "Error when finding an Assignment for this Ticket."
}
},
"description": "An Assignment object represents the assignment associated with a Ticket. Open\nmatch does not require or inspect any fields on assignment."
},
"apiEvaluateProposalsRequest": {
"type": "object",
"properties": {
"matches": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "List of proposals to evaluate in the current synchronization cycle."
},
"id": {
"type": "string",
"description": "Identifier for this request issued during request registration."
}
}
},
"apiEvaluateProposalsResponse": {
"type": "object",
"properties": {
"matches": {
"type": "array",
"items": {
"$ref": "#/definitions/apiMatch"
},
"description": "Results from evaluating proposals for this request."
}
}
},
"apiMatch": {
"type": "object",
"properties": {
"match_id": {
"type": "string",
"description": "A Match ID that should be passed through the stack for tracing."
},
"match_profile": {
"type": "string",
"description": "Name of the match profile that generated this Match."
},
"match_function": {
"type": "string",
"description": "Name of the match function that generated this Match."
},
"tickets": {
"type": "array",
"items": {
"$ref": "#/definitions/apiTicket"
},
"description": "Tickets belonging to this match."
},
"rosters": {
"type": "array",
"items": {
"$ref": "#/definitions/apiRoster"
},
"title": "Set of Rosters that comprise this Match"
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Match properties for this Match. Open Match does not interpret this field."
}
},
"description": "A Match is used to represent a completed match object. It can be generated by\na MatchFunction as a proposal or can be returned by OpenMatch as a result in\nresponse to the FetchMatches call.\nWhen a match is returned by the FetchMatches call, it should contain at least \none ticket to be considered as valid."
},
"apiRegisterResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Identifier for this request valid for the current synchronization cycle."
}
}
},
"apiRoster": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A developer-chosen human-readable name for this Roster."
},
"ticket_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tickets belonging to this Roster."
}
},
"description": "A Roster is a named collection of Ticket IDs. It exists so that a Tickets\nassociated with a Match can be labelled to belong to a team, sub-team etc. It\ncan also be used to represent the current state of a Match in scenarios such\nas backfill, join-in-progress etc."
},
"apiTicket": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Ticket ID generated by Open Match."
},
"properties": {
"$ref": "#/definitions/protobufStruct",
"description": "Properties contains custom info about the ticket. Top level values can be\nused in indexing and filtering to find tickets."
},
"assignment": {
"$ref": "#/definitions/apiAssignment",
"description": "Assignment associated with the Ticket."
}
},
"description": "A Ticket is a basic matchmaking entity in Open Match. In order to enter\nmatchmaking using Open Match, the client should generate a Ticket, passing in\nthe properties to be associated with this Ticket. Open Match will generate an\nID for a Ticket during creation. A Ticket could be used to represent an\nindividual 'Player' or a 'Group' of players. Open Match will not interpret\nwhat the Ticket represents but just treat it as a matchmaking unit with a set\nof properties. Open Match stores the Ticket in state storage and enables an\nAssignment to be associated with this Ticket."
},
"protobufAny": {
"type": "object",
"properties": {
"type_url": {
"type": "string",
"description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics."
},
"value": {
"type": "string",
"format": "byte",
"description": "Must be a valid serialized protocol buffer of the above specified type."
}
},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
},
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
"NULL_VALUE"
],
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32",
"description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]."
},
"message": {
"type": "string",
"description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client."
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
},
"description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use."
}
},
"description": "- Simple to use and understand for most users\n- Flexible enough to meet unexpected needs\n\n# Overview\n\nThe `Status` message contains three pieces of data: error code, error\nmessage, and error details. The error code should be an enum value of\n[google.rpc.Code][google.rpc.Code], but it may accept additional error codes\nif needed. The error message should be a developer-facing English message\nthat helps developers *understand* and *resolve* the error. If a localized\nuser-facing error message is needed, put the localized message in the error\ndetails or localize it in the client. The optional error details may contain\narbitrary information about the error. There is a predefined set of error\ndetail types in the package `google.rpc` that can be used for common error\nconditions.\n\n# Language mapping\n\nThe `Status` message is the logical representation of the error model, but it\nis not necessarily the actual wire format. When the `Status` message is\nexposed in different client libraries and different wire protocols, it can be\nmapped differently. For example, it will likely be mapped to some exceptions\nin Java, but more likely mapped to some error codes in C.\n\n# Other uses\n\nThe error model and the `Status` message can be used in a variety of\nenvironments, either with or without APIs, to provide a\nconsistent developer experience across different environments.\n\nExample uses of this error model include:\n\n- Partial errors. If a service needs to return partial errors to the client,\n it may embed the `Status` in the normal response to indicate the partial\n errors.\n\n- Workflow errors. A typical workflow has multiple steps. Each step may\n have a `Status` message for error reporting.\n\n- Batch operations. If a client uses batch request and batch response, the\n `Status` message should be used directly inside batch response, one for\n each error sub-response.\n\n- Asynchronous operations. If an API call embeds asynchronous operation\n results in its response, the status of those operations should be\n represented directly using the `Status` message.\n\n- Logging. If some API errors are stored in logs, the message `Status` could\n be used directly after any stripping needed for security/privacy reasons.",
"title": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). The error model is designed to be:"
}
},
"externalDocs": {
"description": "Open Match Documentation",
"url": "https://open-match.dev/site/docs/"
}
}

@ -49,12 +49,12 @@
steps:
- id: 'Docker Image: open-match-build'
name: gcr.io/kaniko-project/executor
args: ['--destination=gcr.io/$PROJECT_ID/open-match-build', '--cache=true', '--cache-ttl=48h', '--dockerfile=Dockerfile.ci', '.']
args: ['--destination=gcr.io/$PROJECT_ID/open-match-build', '--cache=true', '--cache-ttl=48h', '--dockerfile=Dockerfile.ci']
waitFor: ['-']
- id: 'Build: Clean'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'clean']
args: ['make', 'clean-third-party', 'clean-protos', 'clean-swagger-docs']
waitFor: ['Docker Image: open-match-build']
- id: 'Test: Markdown'
@ -70,15 +70,7 @@ steps:
path: '/go'
waitFor: ['Build: Clean']
- id: 'Build: Install Kubernetes Tools'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'install-kubernetes-tools']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Build: Clean']
- id: 'Build: Install Toolchain'
- id: 'Build: Initialize Toolchain'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'install-toolchain']
volumes:
@ -86,13 +78,23 @@ steps:
path: '/go'
waitFor: ['Setup: Download Dependencies']
- id: 'Test: Terraform Configuration'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'terraform-test']
waitFor: ['Build: Initialize Toolchain']
- id: 'Build: Deployment Configs'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'SHORT_SHA=${SHORT_SHA}', 'update-chart-deps', 'install/yaml/']
waitFor: ['Build: Initialize Toolchain']
- id: 'Build: Assets'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'assets', '-j12']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Build: Install Toolchain']
waitFor: ['Build: Deployment Configs']
- id: 'Build: Binaries'
name: 'gcr.io/$PROJECT_ID/open-match-build'
@ -115,92 +117,54 @@ steps:
args: ['make', '_GCB_POST_SUBMIT=${_GCB_POST_SUBMIT}', '_GCB_LATEST_VERSION=${_GCB_LATEST_VERSION}', 'SHORT_SHA=${SHORT_SHA}', 'BRANCH_NAME=${BRANCH_NAME}', 'push-images', '-j8']
waitFor: ['Build: Assets']
- id: 'Build: Deployment Configs'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'VERSION_SUFFIX=$SHORT_SHA', 'clean-install-yaml', 'install/yaml/']
waitFor: ['Build: Install Toolchain']
- id: 'Lint: Format, Vet, Charts'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'lint']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Build: Assets', 'Build: Deployment Configs']
- id: 'Test: Terraform Configuration'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'terraform-test']
waitFor: ['Build: Install Toolchain']
- id: 'Test: Create Cluster'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'SHORT_SHA=${SHORT_SHA}', 'delete-gke-cluster', 'create-gke-cluster', 'push-helm']
waitFor: ['Build: Install Kubernetes Tools']
waitFor: ['Build: Assets']
- id: 'Test: Deploy Open Match'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'SHORT_SHA=${SHORT_SHA}', 'install-ci-chart']
waitFor: ['Test: Create Cluster', 'Build: Docker Images']
- id: 'Test: End-to-End Cluster'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'GOPROXY=off', 'SHORT_SHA=${SHORT_SHA}', 'test-e2e-cluster']
waitFor: ['Test: Deploy Open Match', 'Build: Assets']
volumes:
- name: 'go-vol'
path: '/go'
- id: 'Test: Delete Cluster'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'SHORT_SHA=${SHORT_SHA}', 'GCLOUD_EXTRA_FLAGS=--async', 'GCP_PROJECT_ID=${PROJECT_ID}', 'ci-reap-clusters', 'delete-gke-cluster']
waitFor: ['Test: End-to-End Cluster']
args: ['make', 'SHORT_SHA=${SHORT_SHA}', 'OPEN_MATCH_KUBERNETES_NAMESPACE=open-match-${BUILD_ID}', 'OPEN_MATCH_RELEASE_NAME=open-match-${BUILD_ID}', 'auth-gke-cluster', 'delete-chart', 'ci-reap-namespaces', 'install-ci-chart']
waitFor: ['Build: Docker Images']
- id: 'Deploy: Deployment Configs'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', '_GCB_POST_SUBMIT=${_GCB_POST_SUBMIT}', '_GCB_LATEST_VERSION=${_GCB_LATEST_VERSION}', 'VERSION_SUFFIX=${SHORT_SHA}', 'BRANCH_NAME=${BRANCH_NAME}', 'ci-deploy-artifacts']
args: ['make', '_GCB_POST_SUBMIT=${_GCB_POST_SUBMIT}', '_GCB_LATEST_VERSION=${_GCB_LATEST_VERSION}', 'SHORT_SHA=${SHORT_SHA}', 'BRANCH_NAME=${BRANCH_NAME}', 'ci-deploy-artifacts']
waitFor: ['Lint: Format, Vet, Charts', 'Test: Deploy Open Match']
volumes:
- name: 'go-vol'
path: '/go'
- id: 'Test: End-to-End Cluster'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'GOPROXY=off', 'SHORT_SHA=${SHORT_SHA}', 'OPEN_MATCH_KUBERNETES_NAMESPACE=open-match-${BUILD_ID}', 'test-e2e-cluster']
waitFor: ['Test: Deploy Open Match', 'Build: Assets']
volumes:
- name: 'go-vol'
path: '/go'
- id: 'Test: Delete Open Match'
name: 'gcr.io/$PROJECT_ID/open-match-build'
args: ['make', 'GCLOUD_EXTRA_FLAGS=--async', 'SHORT_SHA=${SHORT_SHA}', 'OPEN_MATCH_KUBERNETES_NAMESPACE=open-match-${BUILD_ID}', 'OPEN_MATCH_RELEASE_NAME=open-match-${BUILD_ID}', 'GCP_PROJECT_ID=${PROJECT_ID}', 'delete-chart']
waitFor: ['Test: End-to-End Cluster']
artifacts:
objects:
location: gs://open-match-build-artifacts/output/
paths:
- cmd/backend/backend
- cmd/frontend/frontend
- cmd/mmlogic/mmlogic
- cmd/synchronizer/synchronizer
- cmd/minimatch/minimatch
- cmd/swaggerui/swaggerui
- install/yaml/install.yaml
- install/yaml/install-demo.yaml
- install/yaml/01-redis-chart.yaml
- install/yaml/02-open-match.yaml
- install/yaml/01-open-match-core.yaml
- install/yaml/02-open-match-demo.yaml
- install/yaml/03-prometheus-chart.yaml
- install/yaml/04-grafana-chart.yaml
- install/yaml/05-jaeger-chart.yaml
- examples/functions/golang/soloduel/soloduel
- examples/functions/golang/pool/pool
- examples/evaluator/golang/simple/simple
- tools/certgen/certgen
- tools/reaper/reaper
images:
- 'gcr.io/$PROJECT_ID/openmatch-backend:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-frontend:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmlogic:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-synchronizer:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-minimatch:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-demo:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-go-soloduel:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-go-pool:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-evaluator-go-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-swaggerui:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-reaper:${_OM_VERSION}-${SHORT_SHA}'
- install/yaml/06-open-match-override-configmap.yaml
substitutions:
_OM_VERSION: "0.6.0"
_OM_VERSION: "0.8.0-rc.1"
_GCB_POST_SUBMIT: "0"
_GCB_LATEST_VERSION: "undefined"
logsBucket: 'gs://open-match-build-logs/'

@ -1,56 +0,0 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/backend/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
FROM gcr.io/distroless/static:nonroot
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/backend/backend /app/
ENTRYPOINT ["/app/backend"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Open Match Backend API"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.authors="Google LLC <open-match-discuss@googlegroups.com>" \
org.opencontainers.image.url="https://open-match.dev/" \
org.opencontainers.image.documentation="https://open-match.dev/site/docs/" \
org.opencontainers.image.source="https://github.com/googleforgames/open-match" \
org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.revision="1" \
org.opencontainers.image.vendor="Google LLC" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.ref.name="" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.url="http://open-match.dev/" \
org.label-schema.vcs-url="https://github.com/googleforgames/open-match" \
org.label-schema.version=$BUILD_VERSION \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vendor="Google LLC" \
org.label-schema.name="${IMAGE_TITLE}" \
org.label-schema.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.usage="https://open-match.dev/site/docs/"

@ -0,0 +1,31 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"open-match.dev/open-match/examples/demo"
"open-match.dev/open-match/examples/demo/components"
"open-match.dev/open-match/examples/demo/components/clients"
"open-match.dev/open-match/examples/demo/components/director"
"open-match.dev/open-match/examples/demo/components/uptime"
)
func main() {
demo.Run(map[string]func(*components.DemoShared){
"uptime": uptime.Run,
"clients": clients.Run,
"director": director.Run,
})
}

@ -1,56 +0,0 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/frontend/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
FROM gcr.io/distroless/static:nonroot
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/frontend/frontend /app/
ENTRYPOINT ["/app/frontend"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Open Match Frontend API"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.authors="Google LLC <open-match-discuss@googlegroups.com>" \
org.opencontainers.image.url="https://open-match.dev/" \
org.opencontainers.image.documentation="https://open-match.dev/site/docs/" \
org.opencontainers.image.source="https://github.com/googleforgames/open-match" \
org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.revision="1" \
org.opencontainers.image.vendor="Google LLC" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.ref.name="" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.url="http://open-match.dev/" \
org.label-schema.vcs-url="https://github.com/googleforgames/open-match" \
org.label-schema.version=$BUILD_VERSION \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vendor="Google LLC" \
org.label-schema.name="${IMAGE_TITLE}" \
org.label-schema.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.usage="https://open-match.dev/site/docs/"

@ -1,56 +0,0 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/mmlogic/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
FROM gcr.io/distroless/static:nonroot
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/mmlogic/mmlogic /app/
ENTRYPOINT ["/app/mmlogic"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Open Match Data API"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.authors="Google LLC <open-match-discuss@googlegroups.com>" \
org.opencontainers.image.url="https://open-match.dev/" \
org.opencontainers.image.documentation="https://open-match.dev/site/docs/" \
org.opencontainers.image.source="https://github.com/googleforgames/open-match" \
org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.revision="1" \
org.opencontainers.image.vendor="Google LLC" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.ref.name="" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.url="http://open-match.dev/" \
org.label-schema.vcs-url="https://github.com/googleforgames/open-match" \
org.label-schema.version=$BUILD_VERSION \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vendor="Google LLC" \
org.label-schema.name="${IMAGE_TITLE}" \
org.label-schema.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.usage="https://open-match.dev/site/docs/"

@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package examples defines the constants that some of the examples may share.
package examples
package main
const (
MatchScore = "match_score"
import (
"open-match.dev/open-match/examples/scale/backend"
)
func main() {
backend.Run()
}

@ -0,0 +1,23 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"open-match.dev/open-match/examples/scale/frontend"
)
func main() {
frontend.Run()
}

@ -1,61 +0,0 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/swaggerui/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
COPY api/*.json /go/src/open-match.dev/open-match/third_party/swaggerui/api/
# Since we copy the swagger docs to the container point to them so they are served locally.
# This is important because if there are local changes we want those reflecting in the container.
RUN sed -i 's|https://open-match.dev/api/v.*/|/api/|g' /go/src/open-match.dev/open-match/third_party/swaggerui/config.json
FROM gcr.io/distroless/static:nonroot
WORKDIR /app
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/swaggerui/swaggerui /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/third_party/swaggerui/ /app/static
ENTRYPOINT ["/app/swaggerui"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Open Match Swagger UI"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.authors="Google LLC <open-match-discuss@googlegroups.com>" \
org.opencontainers.image.url="https://open-match.dev/" \
org.opencontainers.image.documentation="https://open-match.dev/site/docs/" \
org.opencontainers.image.source="https://github.com/GoogleCloudPlatform/open-match" \
org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.revision="1" \
org.opencontainers.image.vendor="Google LLC" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.ref.name="" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.url="http://open-match.dev/" \
org.label-schema.vcs-url="https://github.com/GoogleCloudPlatform/open-match" \
org.label-schema.version=$BUILD_VERSION \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vendor="Google LLC" \
org.label-schema.name="${IMAGE_TITLE}" \
org.label-schema.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.usage="https://open-match.dev/site/docs/"

@ -1,56 +0,0 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/cmd/synchronizer/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
FROM gcr.io/distroless/static:nonroot
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/cmd/synchronizer/synchronizer /app/
ENTRYPOINT ["/app/synchronizer"]
# Docker Image Arguments
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION
ARG IMAGE_TITLE="Open Match Synchronizer API"
# Standardized Docker Image Labels
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL \
org.opencontainers.image.created="${BUILD_TIME}" \
org.opencontainers.image.authors="Google LLC <open-match-discuss@googlegroups.com>" \
org.opencontainers.image.url="https://open-match.dev/" \
org.opencontainers.image.documentation="https://open-match.dev/site/docs/" \
org.opencontainers.image.source="https://github.com/googleforgames/open-match" \
org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.revision="1" \
org.opencontainers.image.vendor="Google LLC" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.ref.name="" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.schema-version="1.0" \
org.label-schema.build-date=$BUILD_DATE \
org.label-schema.url="http://open-match.dev/" \
org.label-schema.vcs-url="https://github.com/googleforgames/open-match" \
org.label-schema.version=$BUILD_VERSION \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vendor="Google LLC" \
org.label-schema.name="${IMAGE_TITLE}" \
org.label-schema.description="Flexible, extensible, and scalable video game matchmaking." \
org.label-schema.usage="https://open-match.dev/site/docs/"

@ -0,0 +1,54 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: third_party/protoc-gen-swagger/options/annotations.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Grpc.Gateway.ProtocGenSwagger.Options {
/// <summary>Holder for reflection information generated from third_party/protoc-gen-swagger/options/annotations.proto</summary>
public static partial class AnnotationsReflection {
#region Descriptor
/// <summary>File descriptor for third_party/protoc-gen-swagger/options/annotations.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static AnnotationsReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Cjh0aGlyZF9wYXJ0eS9wcm90b2MtZ2VuLXN3YWdnZXIvb3B0aW9ucy9hbm5v",
"dGF0aW9ucy5wcm90bxInZ3JwYy5nYXRld2F5LnByb3RvY19nZW5fc3dhZ2dl",
"ci5vcHRpb25zGiBnb29nbGUvcHJvdG9idWYvZGVzY3JpcHRvci5wcm90bxoq",
"cHJvdG9jLWdlbi1zd2FnZ2VyL29wdGlvbnMvb3BlbmFwaXYyLnByb3RvOmoK",
"EW9wZW5hcGl2Ml9zd2FnZ2VyEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRp",
"b25zGJIIIAEoCzIwLmdycGMuZ2F0ZXdheS5wcm90b2NfZ2VuX3N3YWdnZXIu",
"b3B0aW9ucy5Td2FnZ2VyOnAKE29wZW5hcGl2Ml9vcGVyYXRpb24SHi5nb29n",
"bGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxiSCCABKAsyMi5ncnBjLmdhdGV3",
"YXkucHJvdG9jX2dlbl9zd2FnZ2VyLm9wdGlvbnMuT3BlcmF0aW9uOmsKEG9w",
"ZW5hcGl2Ml9zY2hlbWESHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlv",
"bnMYkgggASgLMi8uZ3JwYy5nYXRld2F5LnByb3RvY19nZW5fc3dhZ2dlci5v",
"cHRpb25zLlNjaGVtYTplCg1vcGVuYXBpdjJfdGFnEh8uZ29vZ2xlLnByb3Rv",
"YnVmLlNlcnZpY2VPcHRpb25zGJIIIAEoCzIsLmdycGMuZ2F0ZXdheS5wcm90",
"b2NfZ2VuX3N3YWdnZXIub3B0aW9ucy5UYWc6bAoPb3BlbmFwaXYyX2ZpZWxk",
"Eh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxiSCCABKAsyMy5ncnBj",
"LmdhdGV3YXkucHJvdG9jX2dlbl9zd2FnZ2VyLm9wdGlvbnMuSlNPTlNjaGVt",
"YUJDWkFnaXRodWIuY29tL2dycGMtZWNvc3lzdGVtL2dycGMtZ2F0ZXdheS9w",
"cm90b2MtZ2VuLXN3YWdnZXIvb3B0aW9uc2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { pbr::FileDescriptor.DescriptorProtoFileDescriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.Openapiv2Reflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, null));
}
#endregion
}
}
#endregion Designer generated code

834
csharp/OpenMatch/Backend.cs Normal file

@ -0,0 +1,834 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: api/backend.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace OpenMatch {
/// <summary>Holder for reflection information generated from api/backend.proto</summary>
public static partial class BackendReflection {
#region Descriptor
/// <summary>File descriptor for api/backend.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static BackendReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChFhcGkvYmFja2VuZC5wcm90bxIJb3Blbm1hdGNoGhJhcGkvbWVzc2FnZXMu",
"cHJvdG8aHGdvb2dsZS9hcGkvYW5ub3RhdGlvbnMucHJvdG8aLHByb3RvYy1n",
"ZW4tc3dhZ2dlci9vcHRpb25zL2Fubm90YXRpb25zLnByb3RvInYKDkZ1bmN0",
"aW9uQ29uZmlnEgwKBGhvc3QYASABKAkSDAoEcG9ydBgCIAEoBRIsCgR0eXBl",
"GAMgASgOMh4ub3Blbm1hdGNoLkZ1bmN0aW9uQ29uZmlnLlR5cGUiGgoEVHlw",
"ZRIICgRHUlBDEAASCAoEUkVTVBABImsKE0ZldGNoTWF0Y2hlc1JlcXVlc3QS",
"KQoGY29uZmlnGAEgASgLMhkub3Blbm1hdGNoLkZ1bmN0aW9uQ29uZmlnEikK",
"CHByb2ZpbGVzGAIgAygLMhcub3Blbm1hdGNoLk1hdGNoUHJvZmlsZSI3ChRG",
"ZXRjaE1hdGNoZXNSZXNwb25zZRIfCgVtYXRjaBgBIAEoCzIQLm9wZW5tYXRj",
"aC5NYXRjaCJVChRBc3NpZ25UaWNrZXRzUmVxdWVzdBISCgp0aWNrZXRfaWRz",
"GAEgAygJEikKCmFzc2lnbm1lbnQYAiABKAsyFS5vcGVubWF0Y2guQXNzaWdu",
"bWVudCIXChVBc3NpZ25UaWNrZXRzUmVzcG9uc2Uy/QEKB0JhY2tlbmQSdwoM",
"RmV0Y2hNYXRjaGVzEh4ub3Blbm1hdGNoLkZldGNoTWF0Y2hlc1JlcXVlc3Qa",
"Hy5vcGVubWF0Y2guRmV0Y2hNYXRjaGVzUmVzcG9uc2UiJILT5JMCHiIZL3Yx",
"L2JhY2tlbmQvbWF0Y2hlczpmZXRjaDoBKjABEnkKDUFzc2lnblRpY2tldHMS",
"Hy5vcGVubWF0Y2guQXNzaWduVGlja2V0c1JlcXVlc3QaIC5vcGVubWF0Y2gu",
"QXNzaWduVGlja2V0c1Jlc3BvbnNlIiWC0+STAh8iGi92MS9iYWNrZW5kL3Rp",
"Y2tldHM6YXNzaWduOgEqQooDWiBvcGVuLW1hdGNoLmRldi9vcGVuLW1hdGNo",
"L3BrZy9wYqoCCU9wZW5NYXRjaJJB2AISsQEKB0JhY2tlbmQiSQoKT3BlbiBN",
"YXRjaBIWaHR0cHM6Ly9vcGVuLW1hdGNoLmRldhojb3Blbi1tYXRjaC1kaXNj",
"dXNzQGdvb2dsZWdyb3Vwcy5jb20qVgoSQXBhY2hlIDIuMCBMaWNlbnNlEkBo",
"dHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlZm9yZ2FtZXMvb3Blbi1tYXRjaC9i",
"bG9iL21hc3Rlci9MSUNFTlNFMgMxLjAqAgECMhBhcHBsaWNhdGlvbi9qc29u",
"OhBhcHBsaWNhdGlvbi9qc29uUjsKAzQwNBI0CipSZXR1cm5lZCB3aGVuIHRo",
"ZSByZXNvdXJjZSBkb2VzIG5vdCBleGlzdC4SBgoEmgIBB3I9ChhPcGVuIE1h",
"dGNoIERvY3VtZW50YXRpb24SIWh0dHBzOi8vb3Blbi1tYXRjaC5kZXYvc2l0",
"ZS9kb2NzL2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::OpenMatch.MessagesReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.AnnotationsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.FunctionConfig), global::OpenMatch.FunctionConfig.Parser, new[]{ "Host", "Port", "Type" }, null, new[]{ typeof(global::OpenMatch.FunctionConfig.Types.Type) }, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.FetchMatchesRequest), global::OpenMatch.FetchMatchesRequest.Parser, new[]{ "Config", "Profiles" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.FetchMatchesResponse), global::OpenMatch.FetchMatchesResponse.Parser, new[]{ "Match" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.AssignTicketsRequest), global::OpenMatch.AssignTicketsRequest.Parser, new[]{ "TicketIds", "Assignment" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.AssignTicketsResponse), global::OpenMatch.AssignTicketsResponse.Parser, null, null, null, null)
}));
}
#endregion
}
#region Messages
/// <summary>
/// FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF
/// </summary>
public sealed partial class FunctionConfig : pb::IMessage<FunctionConfig> {
private static readonly pb::MessageParser<FunctionConfig> _parser = new pb::MessageParser<FunctionConfig>(() => new FunctionConfig());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<FunctionConfig> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.BackendReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FunctionConfig() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FunctionConfig(FunctionConfig other) : this() {
host_ = other.host_;
port_ = other.port_;
type_ = other.type_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FunctionConfig Clone() {
return new FunctionConfig(this);
}
/// <summary>Field number for the "host" field.</summary>
public const int HostFieldNumber = 1;
private string host_ = "";
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Host {
get { return host_; }
set {
host_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "port" field.</summary>
public const int PortFieldNumber = 2;
private int port_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Port {
get { return port_; }
set {
port_ = value;
}
}
/// <summary>Field number for the "type" field.</summary>
public const int TypeFieldNumber = 3;
private global::OpenMatch.FunctionConfig.Types.Type type_ = 0;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.FunctionConfig.Types.Type Type {
get { return type_; }
set {
type_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as FunctionConfig);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(FunctionConfig other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Host != other.Host) return false;
if (Port != other.Port) return false;
if (Type != other.Type) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Host.Length != 0) hash ^= Host.GetHashCode();
if (Port != 0) hash ^= Port.GetHashCode();
if (Type != 0) hash ^= Type.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (Host.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Host);
}
if (Port != 0) {
output.WriteRawTag(16);
output.WriteInt32(Port);
}
if (Type != 0) {
output.WriteRawTag(24);
output.WriteEnum((int) Type);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Host.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Host);
}
if (Port != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port);
}
if (Type != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(FunctionConfig other) {
if (other == null) {
return;
}
if (other.Host.Length != 0) {
Host = other.Host;
}
if (other.Port != 0) {
Port = other.Port;
}
if (other.Type != 0) {
Type = other.Type;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
Host = input.ReadString();
break;
}
case 16: {
Port = input.ReadInt32();
break;
}
case 24: {
Type = (global::OpenMatch.FunctionConfig.Types.Type) input.ReadEnum();
break;
}
}
}
}
#region Nested types
/// <summary>Container for nested types declared in the FunctionConfig message type.</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public enum Type {
[pbr::OriginalName("GRPC")] Grpc = 0,
[pbr::OriginalName("REST")] Rest = 1,
}
}
#endregion
}
public sealed partial class FetchMatchesRequest : pb::IMessage<FetchMatchesRequest> {
private static readonly pb::MessageParser<FetchMatchesRequest> _parser = new pb::MessageParser<FetchMatchesRequest>(() => new FetchMatchesRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<FetchMatchesRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.BackendReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesRequest(FetchMatchesRequest other) : this() {
config_ = other.config_ != null ? other.config_.Clone() : null;
profiles_ = other.profiles_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesRequest Clone() {
return new FetchMatchesRequest(this);
}
/// <summary>Field number for the "config" field.</summary>
public const int ConfigFieldNumber = 1;
private global::OpenMatch.FunctionConfig config_;
/// <summary>
/// FunctionConfig specifies a MMF address and client type for Backend to establish connections with the MMF
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.FunctionConfig Config {
get { return config_; }
set {
config_ = value;
}
}
/// <summary>Field number for the "profiles" field.</summary>
public const int ProfilesFieldNumber = 2;
private static readonly pb::FieldCodec<global::OpenMatch.MatchProfile> _repeated_profiles_codec
= pb::FieldCodec.ForMessage(18, global::OpenMatch.MatchProfile.Parser);
private readonly pbc::RepeatedField<global::OpenMatch.MatchProfile> profiles_ = new pbc::RepeatedField<global::OpenMatch.MatchProfile>();
/// <summary>
/// MatchProfiles that will be sent to thhe MMF specified in the FunctionConfig.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::OpenMatch.MatchProfile> Profiles {
get { return profiles_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as FetchMatchesRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(FetchMatchesRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Config, other.Config)) return false;
if(!profiles_.Equals(other.profiles_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (config_ != null) hash ^= Config.GetHashCode();
hash ^= profiles_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (config_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Config);
}
profiles_.WriteTo(output, _repeated_profiles_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (config_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Config);
}
size += profiles_.CalculateSize(_repeated_profiles_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(FetchMatchesRequest other) {
if (other == null) {
return;
}
if (other.config_ != null) {
if (config_ == null) {
Config = new global::OpenMatch.FunctionConfig();
}
Config.MergeFrom(other.Config);
}
profiles_.Add(other.profiles_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (config_ == null) {
Config = new global::OpenMatch.FunctionConfig();
}
input.ReadMessage(Config);
break;
}
case 18: {
profiles_.AddEntriesFrom(input, _repeated_profiles_codec);
break;
}
}
}
}
}
public sealed partial class FetchMatchesResponse : pb::IMessage<FetchMatchesResponse> {
private static readonly pb::MessageParser<FetchMatchesResponse> _parser = new pb::MessageParser<FetchMatchesResponse>(() => new FetchMatchesResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<FetchMatchesResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.BackendReflection.Descriptor.MessageTypes[2]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesResponse(FetchMatchesResponse other) : this() {
match_ = other.match_ != null ? other.match_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public FetchMatchesResponse Clone() {
return new FetchMatchesResponse(this);
}
/// <summary>Field number for the "match" field.</summary>
public const int MatchFieldNumber = 1;
private global::OpenMatch.Match match_;
/// <summary>
/// A Match generated by the user-defined MMF with the specified MatchProfiles.
/// A valid Match response will contain at least one ticket.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Match Match {
get { return match_; }
set {
match_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as FetchMatchesResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(FetchMatchesResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Match, other.Match)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (match_ != null) hash ^= Match.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (match_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Match);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (match_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Match);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(FetchMatchesResponse other) {
if (other == null) {
return;
}
if (other.match_ != null) {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
Match.MergeFrom(other.Match);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
input.ReadMessage(Match);
break;
}
}
}
}
}
public sealed partial class AssignTicketsRequest : pb::IMessage<AssignTicketsRequest> {
private static readonly pb::MessageParser<AssignTicketsRequest> _parser = new pb::MessageParser<AssignTicketsRequest>(() => new AssignTicketsRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<AssignTicketsRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.BackendReflection.Descriptor.MessageTypes[3]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsRequest(AssignTicketsRequest other) : this() {
ticketIds_ = other.ticketIds_.Clone();
assignment_ = other.assignment_ != null ? other.assignment_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsRequest Clone() {
return new AssignTicketsRequest(this);
}
/// <summary>Field number for the "ticket_ids" field.</summary>
public const int TicketIdsFieldNumber = 1;
private static readonly pb::FieldCodec<string> _repeated_ticketIds_codec
= pb::FieldCodec.ForString(10);
private readonly pbc::RepeatedField<string> ticketIds_ = new pbc::RepeatedField<string>();
/// <summary>
/// TicketIds is a list of strings representing Open Match generated Ids which apply to an Assignment.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<string> TicketIds {
get { return ticketIds_; }
}
/// <summary>Field number for the "assignment" field.</summary>
public const int AssignmentFieldNumber = 2;
private global::OpenMatch.Assignment assignment_;
/// <summary>
/// An Assignment specifies game connection related information to be associated with the TicketIds.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Assignment Assignment {
get { return assignment_; }
set {
assignment_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as AssignTicketsRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(AssignTicketsRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!ticketIds_.Equals(other.ticketIds_)) return false;
if (!object.Equals(Assignment, other.Assignment)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= ticketIds_.GetHashCode();
if (assignment_ != null) hash ^= Assignment.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
ticketIds_.WriteTo(output, _repeated_ticketIds_codec);
if (assignment_ != null) {
output.WriteRawTag(18);
output.WriteMessage(Assignment);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += ticketIds_.CalculateSize(_repeated_ticketIds_codec);
if (assignment_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Assignment);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(AssignTicketsRequest other) {
if (other == null) {
return;
}
ticketIds_.Add(other.ticketIds_);
if (other.assignment_ != null) {
if (assignment_ == null) {
Assignment = new global::OpenMatch.Assignment();
}
Assignment.MergeFrom(other.Assignment);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
ticketIds_.AddEntriesFrom(input, _repeated_ticketIds_codec);
break;
}
case 18: {
if (assignment_ == null) {
Assignment = new global::OpenMatch.Assignment();
}
input.ReadMessage(Assignment);
break;
}
}
}
}
}
public sealed partial class AssignTicketsResponse : pb::IMessage<AssignTicketsResponse> {
private static readonly pb::MessageParser<AssignTicketsResponse> _parser = new pb::MessageParser<AssignTicketsResponse>(() => new AssignTicketsResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<AssignTicketsResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.BackendReflection.Descriptor.MessageTypes[4]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsResponse(AssignTicketsResponse other) : this() {
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AssignTicketsResponse Clone() {
return new AssignTicketsResponse(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as AssignTicketsResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(AssignTicketsResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(AssignTicketsResponse other) {
if (other == null) {
return;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
}
}
}
}
#endregion
}
#endregion Designer generated code

@ -0,0 +1,336 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: api/evaluator.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace OpenMatch {
/// <summary>Holder for reflection information generated from api/evaluator.proto</summary>
public static partial class EvaluatorReflection {
#region Descriptor
/// <summary>File descriptor for api/evaluator.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static EvaluatorReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChNhcGkvZXZhbHVhdG9yLnByb3RvEglvcGVubWF0Y2gaEmFwaS9tZXNzYWdl",
"cy5wcm90bxocZ29vZ2xlL2FwaS9hbm5vdGF0aW9ucy5wcm90bxoscHJvdG9j",
"LWdlbi1zd2FnZ2VyL29wdGlvbnMvYW5ub3RhdGlvbnMucHJvdG8iMgoPRXZh",
"bHVhdGVSZXF1ZXN0Eh8KBW1hdGNoGAEgASgLMhAub3Blbm1hdGNoLk1hdGNo",
"IjMKEEV2YWx1YXRlUmVzcG9uc2USHwoFbWF0Y2gYASABKAsyEC5vcGVubWF0",
"Y2guTWF0Y2gyfwoJRXZhbHVhdG9yEnIKCEV2YWx1YXRlEhoub3Blbm1hdGNo",
"LkV2YWx1YXRlUmVxdWVzdBobLm9wZW5tYXRjaC5FdmFsdWF0ZVJlc3BvbnNl",
"IimC0+STAiMiHi92MS9ldmFsdWF0b3IvbWF0Y2hlczpldmFsdWF0ZToBKigB",
"MAFCjANaIG9wZW4tbWF0Y2guZGV2L29wZW4tbWF0Y2gvcGtnL3BiqgIJT3Bl",
"bk1hdGNokkHaAhKzAQoJRXZhbHVhdG9yIkkKCk9wZW4gTWF0Y2gSFmh0dHBz",
"Oi8vb3Blbi1tYXRjaC5kZXYaI29wZW4tbWF0Y2gtZGlzY3Vzc0Bnb29nbGVn",
"cm91cHMuY29tKlYKEkFwYWNoZSAyLjAgTGljZW5zZRJAaHR0cHM6Ly9naXRo",
"dWIuY29tL2dvb2dsZWZvcmdhbWVzL29wZW4tbWF0Y2gvYmxvYi9tYXN0ZXIv",
"TElDRU5TRTIDMS4wKgIBAjIQYXBwbGljYXRpb24vanNvbjoQYXBwbGljYXRp",
"b24vanNvblI7CgM0MDQSNAoqUmV0dXJuZWQgd2hlbiB0aGUgcmVzb3VyY2Ug",
"ZG9lcyBub3QgZXhpc3QuEgYKBJoCAQdyPQoYT3BlbiBNYXRjaCBEb2N1bWVu",
"dGF0aW9uEiFodHRwczovL29wZW4tbWF0Y2guZGV2L3NpdGUvZG9jcy9iBnBy",
"b3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::OpenMatch.MessagesReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.AnnotationsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.EvaluateRequest), global::OpenMatch.EvaluateRequest.Parser, new[]{ "Match" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.EvaluateResponse), global::OpenMatch.EvaluateResponse.Parser, new[]{ "Match" }, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class EvaluateRequest : pb::IMessage<EvaluateRequest> {
private static readonly pb::MessageParser<EvaluateRequest> _parser = new pb::MessageParser<EvaluateRequest>(() => new EvaluateRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<EvaluateRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.EvaluatorReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateRequest(EvaluateRequest other) : this() {
match_ = other.match_ != null ? other.match_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateRequest Clone() {
return new EvaluateRequest(this);
}
/// <summary>Field number for the "match" field.</summary>
public const int MatchFieldNumber = 1;
private global::OpenMatch.Match match_;
/// <summary>
/// A Matches proposed by the Match Function representing a candidate of the final results.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Match Match {
get { return match_; }
set {
match_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as EvaluateRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(EvaluateRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Match, other.Match)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (match_ != null) hash ^= Match.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (match_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Match);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (match_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Match);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(EvaluateRequest other) {
if (other == null) {
return;
}
if (other.match_ != null) {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
Match.MergeFrom(other.Match);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
input.ReadMessage(Match);
break;
}
}
}
}
}
public sealed partial class EvaluateResponse : pb::IMessage<EvaluateResponse> {
private static readonly pb::MessageParser<EvaluateResponse> _parser = new pb::MessageParser<EvaluateResponse>(() => new EvaluateResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<EvaluateResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.EvaluatorReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateResponse(EvaluateResponse other) : this() {
match_ = other.match_ != null ? other.match_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public EvaluateResponse Clone() {
return new EvaluateResponse(this);
}
/// <summary>Field number for the "match" field.</summary>
public const int MatchFieldNumber = 1;
private global::OpenMatch.Match match_;
/// <summary>
/// A Match shortlisted by the evaluator representing one of the final results.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Match Match {
get { return match_; }
set {
match_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as EvaluateResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(EvaluateResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Match, other.Match)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (match_ != null) hash ^= Match.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (match_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Match);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (match_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Match);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(EvaluateResponse other) {
if (other == null) {
return;
}
if (other.match_ != null) {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
Match.MergeFrom(other.Match);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (match_ == null) {
Match = new global::OpenMatch.Match();
}
input.ReadMessage(Match);
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code

@ -0,0 +1,989 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: api/frontend.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace OpenMatch {
/// <summary>Holder for reflection information generated from api/frontend.proto</summary>
public static partial class FrontendReflection {
#region Descriptor
/// <summary>File descriptor for api/frontend.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static FrontendReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChJhcGkvZnJvbnRlbmQucHJvdG8SCW9wZW5tYXRjaBoSYXBpL21lc3NhZ2Vz",
"LnByb3RvGhxnb29nbGUvYXBpL2Fubm90YXRpb25zLnByb3RvGixwcm90b2Mt",
"Z2VuLXN3YWdnZXIvb3B0aW9ucy9hbm5vdGF0aW9ucy5wcm90byI4ChNDcmVh",
"dGVUaWNrZXRSZXF1ZXN0EiEKBnRpY2tldBgBIAEoCzIRLm9wZW5tYXRjaC5U",
"aWNrZXQiOQoUQ3JlYXRlVGlja2V0UmVzcG9uc2USIQoGdGlja2V0GAEgASgL",
"MhEub3Blbm1hdGNoLlRpY2tldCIoChNEZWxldGVUaWNrZXRSZXF1ZXN0EhEK",
"CXRpY2tldF9pZBgBIAEoCSIWChREZWxldGVUaWNrZXRSZXNwb25zZSIlChBH",
"ZXRUaWNrZXRSZXF1ZXN0EhEKCXRpY2tldF9pZBgBIAEoCSIqChVHZXRBc3Np",
"Z25tZW50c1JlcXVlc3QSEQoJdGlja2V0X2lkGAEgASgJIkMKFkdldEFzc2ln",
"bm1lbnRzUmVzcG9uc2USKQoKYXNzaWdubWVudBgBIAEoCzIVLm9wZW5tYXRj",
"aC5Bc3NpZ25tZW50Mu4DCghGcm9udGVuZBJwCgxDcmVhdGVUaWNrZXQSHi5v",
"cGVubWF0Y2guQ3JlYXRlVGlja2V0UmVxdWVzdBofLm9wZW5tYXRjaC5DcmVh",
"dGVUaWNrZXRSZXNwb25zZSIfgtPkkwIZIhQvdjEvZnJvbnRlbmQvdGlja2V0",
"czoBKhJ5CgxEZWxldGVUaWNrZXQSHi5vcGVubWF0Y2guRGVsZXRlVGlja2V0",
"UmVxdWVzdBofLm9wZW5tYXRjaC5EZWxldGVUaWNrZXRSZXNwb25zZSIogtPk",
"kwIiKiAvdjEvZnJvbnRlbmQvdGlja2V0cy97dGlja2V0X2lkfRJlCglHZXRU",
"aWNrZXQSGy5vcGVubWF0Y2guR2V0VGlja2V0UmVxdWVzdBoRLm9wZW5tYXRj",
"aC5UaWNrZXQiKILT5JMCIhIgL3YxL2Zyb250ZW5kL3RpY2tldHMve3RpY2tl",
"dF9pZH0SjQEKDkdldEFzc2lnbm1lbnRzEiAub3Blbm1hdGNoLkdldEFzc2ln",
"bm1lbnRzUmVxdWVzdBohLm9wZW5tYXRjaC5HZXRBc3NpZ25tZW50c1Jlc3Bv",
"bnNlIjSC0+STAi4SLC92MS9mcm9udGVuZC90aWNrZXRzL3t0aWNrZXRfaWR9",
"L2Fzc2lnbm1lbnRzMAFCiwNaIG9wZW4tbWF0Y2guZGV2L29wZW4tbWF0Y2gv",
"cGtnL3BiqgIJT3Blbk1hdGNokkHZAhKyAQoIRnJvbnRlbmQiSQoKT3BlbiBN",
"YXRjaBIWaHR0cHM6Ly9vcGVuLW1hdGNoLmRldhojb3Blbi1tYXRjaC1kaXNj",
"dXNzQGdvb2dsZWdyb3Vwcy5jb20qVgoSQXBhY2hlIDIuMCBMaWNlbnNlEkBo",
"dHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlZm9yZ2FtZXMvb3Blbi1tYXRjaC9i",
"bG9iL21hc3Rlci9MSUNFTlNFMgMxLjAqAgECMhBhcHBsaWNhdGlvbi9qc29u",
"OhBhcHBsaWNhdGlvbi9qc29uUjsKAzQwNBI0CipSZXR1cm5lZCB3aGVuIHRo",
"ZSByZXNvdXJjZSBkb2VzIG5vdCBleGlzdC4SBgoEmgIBB3I9ChhPcGVuIE1h",
"dGNoIERvY3VtZW50YXRpb24SIWh0dHBzOi8vb3Blbi1tYXRjaC5kZXYvc2l0",
"ZS9kb2NzL2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::OpenMatch.MessagesReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.AnnotationsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.CreateTicketRequest), global::OpenMatch.CreateTicketRequest.Parser, new[]{ "Ticket" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.CreateTicketResponse), global::OpenMatch.CreateTicketResponse.Parser, new[]{ "Ticket" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.DeleteTicketRequest), global::OpenMatch.DeleteTicketRequest.Parser, new[]{ "TicketId" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.DeleteTicketResponse), global::OpenMatch.DeleteTicketResponse.Parser, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.GetTicketRequest), global::OpenMatch.GetTicketRequest.Parser, new[]{ "TicketId" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.GetAssignmentsRequest), global::OpenMatch.GetAssignmentsRequest.Parser, new[]{ "TicketId" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.GetAssignmentsResponse), global::OpenMatch.GetAssignmentsResponse.Parser, new[]{ "Assignment" }, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class CreateTicketRequest : pb::IMessage<CreateTicketRequest> {
private static readonly pb::MessageParser<CreateTicketRequest> _parser = new pb::MessageParser<CreateTicketRequest>(() => new CreateTicketRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<CreateTicketRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketRequest(CreateTicketRequest other) : this() {
ticket_ = other.ticket_ != null ? other.ticket_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketRequest Clone() {
return new CreateTicketRequest(this);
}
/// <summary>Field number for the "ticket" field.</summary>
public const int TicketFieldNumber = 1;
private global::OpenMatch.Ticket ticket_;
/// <summary>
/// A Ticket object with SearchFields defined.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Ticket Ticket {
get { return ticket_; }
set {
ticket_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as CreateTicketRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(CreateTicketRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Ticket, other.Ticket)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (ticket_ != null) hash ^= Ticket.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (ticket_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Ticket);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (ticket_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Ticket);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(CreateTicketRequest other) {
if (other == null) {
return;
}
if (other.ticket_ != null) {
if (ticket_ == null) {
Ticket = new global::OpenMatch.Ticket();
}
Ticket.MergeFrom(other.Ticket);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (ticket_ == null) {
Ticket = new global::OpenMatch.Ticket();
}
input.ReadMessage(Ticket);
break;
}
}
}
}
}
public sealed partial class CreateTicketResponse : pb::IMessage<CreateTicketResponse> {
private static readonly pb::MessageParser<CreateTicketResponse> _parser = new pb::MessageParser<CreateTicketResponse>(() => new CreateTicketResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<CreateTicketResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketResponse(CreateTicketResponse other) : this() {
ticket_ = other.ticket_ != null ? other.ticket_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public CreateTicketResponse Clone() {
return new CreateTicketResponse(this);
}
/// <summary>Field number for the "ticket" field.</summary>
public const int TicketFieldNumber = 1;
private global::OpenMatch.Ticket ticket_;
/// <summary>
/// A Ticket object with TicketId generated.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Ticket Ticket {
get { return ticket_; }
set {
ticket_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as CreateTicketResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(CreateTicketResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Ticket, other.Ticket)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (ticket_ != null) hash ^= Ticket.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (ticket_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Ticket);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (ticket_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Ticket);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(CreateTicketResponse other) {
if (other == null) {
return;
}
if (other.ticket_ != null) {
if (ticket_ == null) {
Ticket = new global::OpenMatch.Ticket();
}
Ticket.MergeFrom(other.Ticket);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (ticket_ == null) {
Ticket = new global::OpenMatch.Ticket();
}
input.ReadMessage(Ticket);
break;
}
}
}
}
}
public sealed partial class DeleteTicketRequest : pb::IMessage<DeleteTicketRequest> {
private static readonly pb::MessageParser<DeleteTicketRequest> _parser = new pb::MessageParser<DeleteTicketRequest>(() => new DeleteTicketRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<DeleteTicketRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[2]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketRequest(DeleteTicketRequest other) : this() {
ticketId_ = other.ticketId_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketRequest Clone() {
return new DeleteTicketRequest(this);
}
/// <summary>Field number for the "ticket_id" field.</summary>
public const int TicketIdFieldNumber = 1;
private string ticketId_ = "";
/// <summary>
/// A TicketId of a generated Ticket to be deleted.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string TicketId {
get { return ticketId_; }
set {
ticketId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DeleteTicketRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DeleteTicketRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (TicketId != other.TicketId) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (TicketId.Length != 0) hash ^= TicketId.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (TicketId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(TicketId);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (TicketId.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TicketId);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DeleteTicketRequest other) {
if (other == null) {
return;
}
if (other.TicketId.Length != 0) {
TicketId = other.TicketId;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
TicketId = input.ReadString();
break;
}
}
}
}
}
public sealed partial class DeleteTicketResponse : pb::IMessage<DeleteTicketResponse> {
private static readonly pb::MessageParser<DeleteTicketResponse> _parser = new pb::MessageParser<DeleteTicketResponse>(() => new DeleteTicketResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<DeleteTicketResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[3]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketResponse(DeleteTicketResponse other) : this() {
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DeleteTicketResponse Clone() {
return new DeleteTicketResponse(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DeleteTicketResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DeleteTicketResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DeleteTicketResponse other) {
if (other == null) {
return;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
}
}
}
}
public sealed partial class GetTicketRequest : pb::IMessage<GetTicketRequest> {
private static readonly pb::MessageParser<GetTicketRequest> _parser = new pb::MessageParser<GetTicketRequest>(() => new GetTicketRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GetTicketRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[4]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetTicketRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetTicketRequest(GetTicketRequest other) : this() {
ticketId_ = other.ticketId_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetTicketRequest Clone() {
return new GetTicketRequest(this);
}
/// <summary>Field number for the "ticket_id" field.</summary>
public const int TicketIdFieldNumber = 1;
private string ticketId_ = "";
/// <summary>
/// A TicketId of a generated Ticket.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string TicketId {
get { return ticketId_; }
set {
ticketId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GetTicketRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GetTicketRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (TicketId != other.TicketId) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (TicketId.Length != 0) hash ^= TicketId.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (TicketId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(TicketId);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (TicketId.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TicketId);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GetTicketRequest other) {
if (other == null) {
return;
}
if (other.TicketId.Length != 0) {
TicketId = other.TicketId;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
TicketId = input.ReadString();
break;
}
}
}
}
}
public sealed partial class GetAssignmentsRequest : pb::IMessage<GetAssignmentsRequest> {
private static readonly pb::MessageParser<GetAssignmentsRequest> _parser = new pb::MessageParser<GetAssignmentsRequest>(() => new GetAssignmentsRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GetAssignmentsRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[5]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsRequest(GetAssignmentsRequest other) : this() {
ticketId_ = other.ticketId_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsRequest Clone() {
return new GetAssignmentsRequest(this);
}
/// <summary>Field number for the "ticket_id" field.</summary>
public const int TicketIdFieldNumber = 1;
private string ticketId_ = "";
/// <summary>
/// A TicketId of a generated Ticket to get updates on.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string TicketId {
get { return ticketId_; }
set {
ticketId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GetAssignmentsRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GetAssignmentsRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (TicketId != other.TicketId) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (TicketId.Length != 0) hash ^= TicketId.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (TicketId.Length != 0) {
output.WriteRawTag(10);
output.WriteString(TicketId);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (TicketId.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TicketId);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GetAssignmentsRequest other) {
if (other == null) {
return;
}
if (other.TicketId.Length != 0) {
TicketId = other.TicketId;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
TicketId = input.ReadString();
break;
}
}
}
}
}
public sealed partial class GetAssignmentsResponse : pb::IMessage<GetAssignmentsResponse> {
private static readonly pb::MessageParser<GetAssignmentsResponse> _parser = new pb::MessageParser<GetAssignmentsResponse>(() => new GetAssignmentsResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GetAssignmentsResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.FrontendReflection.Descriptor.MessageTypes[6]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsResponse(GetAssignmentsResponse other) : this() {
assignment_ = other.assignment_ != null ? other.assignment_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetAssignmentsResponse Clone() {
return new GetAssignmentsResponse(this);
}
/// <summary>Field number for the "assignment" field.</summary>
public const int AssignmentFieldNumber = 1;
private global::OpenMatch.Assignment assignment_;
/// <summary>
/// An updated Assignment of the requested Ticket.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Assignment Assignment {
get { return assignment_; }
set {
assignment_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GetAssignmentsResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GetAssignmentsResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Assignment, other.Assignment)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (assignment_ != null) hash ^= Assignment.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (assignment_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Assignment);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (assignment_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Assignment);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GetAssignmentsResponse other) {
if (other == null) {
return;
}
if (other.assignment_ != null) {
if (assignment_ == null) {
Assignment = new global::OpenMatch.Assignment();
}
Assignment.MergeFrom(other.Assignment);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (assignment_ == null) {
Assignment = new global::OpenMatch.Assignment();
}
input.ReadMessage(Assignment);
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code

@ -0,0 +1,336 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: api/matchfunction.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace OpenMatch {
/// <summary>Holder for reflection information generated from api/matchfunction.proto</summary>
public static partial class MatchfunctionReflection {
#region Descriptor
/// <summary>File descriptor for api/matchfunction.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static MatchfunctionReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChdhcGkvbWF0Y2hmdW5jdGlvbi5wcm90bxIJb3Blbm1hdGNoGhJhcGkvbWVz",
"c2FnZXMucHJvdG8aHGdvb2dsZS9hcGkvYW5ub3RhdGlvbnMucHJvdG8aLHBy",
"b3RvYy1nZW4tc3dhZ2dlci9vcHRpb25zL2Fubm90YXRpb25zLnByb3RvIjYK",
"ClJ1blJlcXVlc3QSKAoHcHJvZmlsZRgBIAEoCzIXLm9wZW5tYXRjaC5NYXRj",
"aFByb2ZpbGUiMQoLUnVuUmVzcG9uc2USIgoIcHJvcG9zYWwYASABKAsyEC5v",
"cGVubWF0Y2guTWF0Y2gyaQoNTWF0Y2hGdW5jdGlvbhJYCgNSdW4SFS5vcGVu",
"bWF0Y2guUnVuUmVxdWVzdBoWLm9wZW5tYXRjaC5SdW5SZXNwb25zZSIggtPk",
"kwIaIhUvdjEvbWF0Y2hmdW5jdGlvbjpydW46ASowAUKRA1ogb3Blbi1tYXRj",
"aC5kZXYvb3Blbi1tYXRjaC9wa2cvcGKqAglPcGVuTWF0Y2iSQd8CErgBCg5N",
"YXRjaCBGdW5jdGlvbiJJCgpPcGVuIE1hdGNoEhZodHRwczovL29wZW4tbWF0",
"Y2guZGV2GiNvcGVuLW1hdGNoLWRpc2N1c3NAZ29vZ2xlZ3JvdXBzLmNvbSpW",
"ChJBcGFjaGUgMi4wIExpY2Vuc2USQGh0dHBzOi8vZ2l0aHViLmNvbS9nb29n",
"bGVmb3JnYW1lcy9vcGVuLW1hdGNoL2Jsb2IvbWFzdGVyL0xJQ0VOU0UyAzEu",
"MCoCAQIyEGFwcGxpY2F0aW9uL2pzb246EGFwcGxpY2F0aW9uL2pzb25SOwoD",
"NDA0EjQKKlJldHVybmVkIHdoZW4gdGhlIHJlc291cmNlIGRvZXMgbm90IGV4",
"aXN0LhIGCgSaAgEHcj0KGE9wZW4gTWF0Y2ggRG9jdW1lbnRhdGlvbhIhaHR0",
"cHM6Ly9vcGVuLW1hdGNoLmRldi9zaXRlL2RvY3MvYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::OpenMatch.MessagesReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.AnnotationsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.RunRequest), global::OpenMatch.RunRequest.Parser, new[]{ "Profile" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.RunResponse), global::OpenMatch.RunResponse.Parser, new[]{ "Proposal" }, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class RunRequest : pb::IMessage<RunRequest> {
private static readonly pb::MessageParser<RunRequest> _parser = new pb::MessageParser<RunRequest>(() => new RunRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<RunRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.MatchfunctionReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunRequest(RunRequest other) : this() {
profile_ = other.profile_ != null ? other.profile_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunRequest Clone() {
return new RunRequest(this);
}
/// <summary>Field number for the "profile" field.</summary>
public const int ProfileFieldNumber = 1;
private global::OpenMatch.MatchProfile profile_;
/// <summary>
/// A MatchProfile defines constraints of Tickets in a Match and shapes the Match proposed by the MatchFunction.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.MatchProfile Profile {
get { return profile_; }
set {
profile_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as RunRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(RunRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Profile, other.Profile)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (profile_ != null) hash ^= Profile.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (profile_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Profile);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (profile_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Profile);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(RunRequest other) {
if (other == null) {
return;
}
if (other.profile_ != null) {
if (profile_ == null) {
Profile = new global::OpenMatch.MatchProfile();
}
Profile.MergeFrom(other.Profile);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (profile_ == null) {
Profile = new global::OpenMatch.MatchProfile();
}
input.ReadMessage(Profile);
break;
}
}
}
}
}
public sealed partial class RunResponse : pb::IMessage<RunResponse> {
private static readonly pb::MessageParser<RunResponse> _parser = new pb::MessageParser<RunResponse>(() => new RunResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<RunResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.MatchfunctionReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunResponse(RunResponse other) : this() {
proposal_ = other.proposal_ != null ? other.proposal_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public RunResponse Clone() {
return new RunResponse(this);
}
/// <summary>Field number for the "proposal" field.</summary>
public const int ProposalFieldNumber = 1;
private global::OpenMatch.Match proposal_;
/// <summary>
/// A Proposal represents a Match candidate that satifies the constraints defined in the input Profile.
/// A valid Proposal response will contain at least one ticket.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Match Proposal {
get { return proposal_; }
set {
proposal_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as RunResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(RunResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Proposal, other.Proposal)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (proposal_ != null) hash ^= Proposal.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (proposal_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Proposal);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (proposal_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Proposal);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(RunResponse other) {
if (other == null) {
return;
}
if (other.proposal_ != null) {
if (proposal_ == null) {
Proposal = new global::OpenMatch.Match();
}
Proposal.MergeFrom(other.Proposal);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (proposal_ == null) {
Proposal = new global::OpenMatch.Match();
}
input.ReadMessage(Proposal);
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code

2065
csharp/OpenMatch/Messages.cs Normal file

File diff suppressed because it is too large Load Diff

322
csharp/OpenMatch/Mmlogic.cs Normal file

@ -0,0 +1,322 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: api/mmlogic.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace OpenMatch {
/// <summary>Holder for reflection information generated from api/mmlogic.proto</summary>
public static partial class MmlogicReflection {
#region Descriptor
/// <summary>File descriptor for api/mmlogic.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static MmlogicReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChFhcGkvbW1sb2dpYy5wcm90bxIJb3Blbm1hdGNoGhJhcGkvbWVzc2FnZXMu",
"cHJvdG8aHGdvb2dsZS9hcGkvYW5ub3RhdGlvbnMucHJvdG8aLHByb3RvYy1n",
"ZW4tc3dhZ2dlci9vcHRpb25zL2Fubm90YXRpb25zLnByb3RvIjQKE1F1ZXJ5",
"VGlja2V0c1JlcXVlc3QSHQoEcG9vbBgBIAEoCzIPLm9wZW5tYXRjaC5Qb29s",
"IjoKFFF1ZXJ5VGlja2V0c1Jlc3BvbnNlEiIKB3RpY2tldHMYASADKAsyES5v",
"cGVubWF0Y2guVGlja2V0MoIBCgdNbUxvZ2ljEncKDFF1ZXJ5VGlja2V0cxIe",
"Lm9wZW5tYXRjaC5RdWVyeVRpY2tldHNSZXF1ZXN0Gh8ub3Blbm1hdGNoLlF1",
"ZXJ5VGlja2V0c1Jlc3BvbnNlIiSC0+STAh4iGS92MS9tbWxvZ2ljL3RpY2tl",
"dHM6cXVlcnk6ASowAUKYA1ogb3Blbi1tYXRjaC5kZXYvb3Blbi1tYXRjaC9w",
"a2cvcGKqAglPcGVuTWF0Y2iSQeYCEr8BChVNTSBMb2dpYyAoRGF0YSBMYXll",
"cikiSQoKT3BlbiBNYXRjaBIWaHR0cHM6Ly9vcGVuLW1hdGNoLmRldhojb3Bl",
"bi1tYXRjaC1kaXNjdXNzQGdvb2dsZWdyb3Vwcy5jb20qVgoSQXBhY2hlIDIu",
"MCBMaWNlbnNlEkBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlZm9yZ2FtZXMv",
"b3Blbi1tYXRjaC9ibG9iL21hc3Rlci9MSUNFTlNFMgMxLjAqAgECMhBhcHBs",
"aWNhdGlvbi9qc29uOhBhcHBsaWNhdGlvbi9qc29uUjsKAzQwNBI0CipSZXR1",
"cm5lZCB3aGVuIHRoZSByZXNvdXJjZSBkb2VzIG5vdCBleGlzdC4SBgoEmgIB",
"B3I9ChhPcGVuIE1hdGNoIERvY3VtZW50YXRpb24SIWh0dHBzOi8vb3Blbi1t",
"YXRjaC5kZXYvc2l0ZS9kb2NzL2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::OpenMatch.MessagesReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, global::Grpc.Gateway.ProtocGenSwagger.Options.AnnotationsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.QueryTicketsRequest), global::OpenMatch.QueryTicketsRequest.Parser, new[]{ "Pool" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::OpenMatch.QueryTicketsResponse), global::OpenMatch.QueryTicketsResponse.Parser, new[]{ "Tickets" }, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class QueryTicketsRequest : pb::IMessage<QueryTicketsRequest> {
private static readonly pb::MessageParser<QueryTicketsRequest> _parser = new pb::MessageParser<QueryTicketsRequest>(() => new QueryTicketsRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<QueryTicketsRequest> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.MmlogicReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsRequest() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsRequest(QueryTicketsRequest other) : this() {
pool_ = other.pool_ != null ? other.pool_.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsRequest Clone() {
return new QueryTicketsRequest(this);
}
/// <summary>Field number for the "pool" field.</summary>
public const int PoolFieldNumber = 1;
private global::OpenMatch.Pool pool_;
/// <summary>
/// A Pool is consists of a set of Filters.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public global::OpenMatch.Pool Pool {
get { return pool_; }
set {
pool_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as QueryTicketsRequest);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(QueryTicketsRequest other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Pool, other.Pool)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (pool_ != null) hash ^= Pool.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
if (pool_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Pool);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (pool_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pool);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(QueryTicketsRequest other) {
if (other == null) {
return;
}
if (other.pool_ != null) {
if (pool_ == null) {
Pool = new global::OpenMatch.Pool();
}
Pool.MergeFrom(other.Pool);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
if (pool_ == null) {
Pool = new global::OpenMatch.Pool();
}
input.ReadMessage(Pool);
break;
}
}
}
}
}
public sealed partial class QueryTicketsResponse : pb::IMessage<QueryTicketsResponse> {
private static readonly pb::MessageParser<QueryTicketsResponse> _parser = new pb::MessageParser<QueryTicketsResponse>(() => new QueryTicketsResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<QueryTicketsResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::OpenMatch.MmlogicReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsResponse(QueryTicketsResponse other) : this() {
tickets_ = other.tickets_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public QueryTicketsResponse Clone() {
return new QueryTicketsResponse(this);
}
/// <summary>Field number for the "tickets" field.</summary>
public const int TicketsFieldNumber = 1;
private static readonly pb::FieldCodec<global::OpenMatch.Ticket> _repeated_tickets_codec
= pb::FieldCodec.ForMessage(10, global::OpenMatch.Ticket.Parser);
private readonly pbc::RepeatedField<global::OpenMatch.Ticket> tickets_ = new pbc::RepeatedField<global::OpenMatch.Ticket>();
/// <summary>
/// Tickets is a list of Ticket representing one or more Tickets which meet all Filter criterias.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::OpenMatch.Ticket> Tickets {
get { return tickets_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as QueryTicketsResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(QueryTicketsResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!tickets_.Equals(other.tickets_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= tickets_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
tickets_.WriteTo(output, _repeated_tickets_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += tickets_.CalculateSize(_repeated_tickets_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(QueryTicketsResponse other) {
if (other == null) {
return;
}
tickets_.Add(other.tickets_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
tickets_.AddEntriesFrom(input, _repeated_tickets_codec);
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>OpenMatch</PackageId>
<Version>0.0.0-dev</Version>
<Authors>Google LLC</Authors>
<Company>Google LLC</Company>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Api.CommonProtos" Version="1.7.0" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -7,16 +7,17 @@ Check the [README](https://github.com/googleforgames/open-match/tree/release-{ve
Release Notes
-------------
{ insert enhancements from the changelog and/or security and breaking changes }
**Feature Highlights**
{ highlight here the most notable changes and themes at a high level}
**Breaking Changes**
* API Changed #PR
**Enhancements**
* New Harness #PR
{ detail any behaviors or API surfaces which worked in a previous version which will no longer work correctly }
**Security Fixes**
* Reduced privileges required for MMF. #PR
{ list any changes which fix vulnerabilities in open match }
**Enhancements**
{ go into details on improvements and changes }
See [CHANGELOG](https://github.com/googleforgames/open-match/blob/release-{version}/CHANGELOG.md) for more details on changes.
@ -25,21 +26,20 @@ Images
```bash
# Servers
docker pull gcr.io/open-match-public-images/openmatch-backendapi:{version}
docker pull gcr.io/open-match-public-images/openmatch-frontendapi:{version}
docker pull gcr.io/open-match-public-images/openmatch-mmforc:{version}
docker pull gcr.io/open-match-public-images/openmatch-mmlogicapi:{version}
docker pull gcr.io/open-match-public-images/openmatch-backend:{version}
docker pull gcr.io/open-match-public-images/openmatch-frontend:{version}
docker pull gcr.io/open-match-public-images/openmatch-mmlogic:{version}
docker pull gcr.io/open-match-public-images/openmatch-synchronizer:{version}
# Evaluators
docker pull gcr.io/open-match-public-images/openmatch-evaluator-serving:{version}
docker pull gcr.io/open-match-public-images/openmatch-evaluator-go-simple:{version}
# Sample Match Making Functions
docker pull gcr.io/open-match-public-images/openmatch-mmf-go-simple:{version}
docker pull gcr.io/open-match-public-images/openmatch-mmf-go-soloduel:{version}
docker pull gcr.io/open-match-public-images/openmatch-mmf-go-pool:{version}
# Test Clients
docker pull gcr.io/open-match-public-images/openmatch-backendclient:{version}
docker pull gcr.io/open-match-public-images/openmatch-clientloadgen:{version}
docker pull gcr.io/open-match-public-images/openmatch-frontendclient:{version}
docker pull gcr.io/open-match-public-images/openmatch-demo-first-match:{version}
```
_This software is currently alpha, and subject to change. Not to be used in production systems._
@ -54,8 +54,8 @@ To deploy Open Match in your Kubernetes cluster run the following commands:
kubectl create clusterrolebinding myname-cluster-admin-binding --clusterrole=cluster-admin --user=$(YOUR_KUBERNETES_USER_NAME)
# Place all Open Match components in their own namespace.
kubectl create namespace open-match
# Install Open Match and monitoring services.
kubectl apply -f https://github.com/googleforgames/open-match/releases/download/v{version}/install.yaml --namespace open-match
# Install Open Match services.
kubectl apply -f https://github.com/googleforgames/open-match/releases/download/v{version}/01-open-match-core.yaml --namespace open-match
# Install the demo.
kubectl apply -f https://github.com/googleforgames/open-match/releases/download/v{version}/install-demo.yaml --namespace open-match
kubectl apply -f https://github.com/googleforgames/open-match/releases/download/v{version}/02-open-match-demo.yaml --namespace open-match
```

@ -12,7 +12,7 @@ SOURCE_VERSION=$1
DEST_VERSION=$2
SOURCE_PROJECT_ID=open-match-build
DEST_PROJECT_ID=open-match-public-images
IMAGE_NAMES="openmatch-backendapi openmatch-frontendapi openmatch-mmforc openmatch-mmlogicapi openmatch-evaluator-serving openmatch-mmf-go-simple openmatch-backendclient openmatch-clientloadgen openmatch-frontendclient"
IMAGE_NAMES="openmatch-backend openmatch-frontend openmatch-mmlogic openmatch-synchronizer openmatch-minimatch openmatch-demo-first-match openmatch-mmf-go-soloduel openmatch-mmf-go-pool openmatch-evaluator-go-simple openmatch-swaggerui openmatch-reaper"
for name in $IMAGE_NAMES
do

@ -20,12 +20,11 @@ import (
"math/rand"
"time"
"google.golang.org/grpc"
"open-match.dev/open-match/examples/demo/components"
"open-match.dev/open-match/examples/demo/updater"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/rpc"
"open-match.dev/open-match/pkg/pb"
"open-match.dev/open-match/pkg/structs"
)
func Run(ds *components.DemoShared) {
@ -35,7 +34,7 @@ func Run(ds *components.DemoShared) {
name := fmt.Sprintf("fakeplayer_%d", i)
go func() {
for !isContextDone(ds.Ctx) {
runScenario(ds.Ctx, ds.Cfg, name, u.ForField(name))
runScenario(ds.Ctx, name, u.ForField(name))
}
}()
}
@ -55,7 +54,7 @@ type status struct {
Assignment *pb.Assignment
}
func runScenario(ctx context.Context, cfg config.View, name string, update updater.SetFunc) {
func runScenario(ctx context.Context, name string, update updater.SetFunc) {
defer func() {
r := recover()
if r != nil {
@ -81,7 +80,8 @@ func runScenario(ctx context.Context, cfg config.View, name string, update updat
s.Status = "Connecting to Open Match frontend"
update(s)
conn, err := rpc.GRPCClientFromConfig(cfg, "api.frontend")
// See https://open-match.dev/site/docs/guides/api/
conn, err := grpc.Dial("om-frontend.open-match.svc.cluster.local:50504", grpc.WithInsecure())
if err != nil {
panic(err)
}
@ -95,12 +95,7 @@ func runScenario(ctx context.Context, cfg config.View, name string, update updat
var ticketId string
{
req := &pb.CreateTicketRequest{
Ticket: &pb.Ticket{
Properties: structs.Struct{
"name": structs.String(name),
"mode.demo": structs.Number(1),
}.S(),
},
Ticket: &pb.Ticket{},
}
resp, err := fe.CreateTicket(ctx, req)

@ -18,11 +18,9 @@ import (
"context"
"open-match.dev/open-match/examples/demo/updater"
"open-match.dev/open-match/internal/config"
)
type DemoShared struct {
Ctx context.Context
Cfg config.View
Update updater.SetFunc
}

@ -17,11 +17,12 @@ package director
import (
"context"
"fmt"
"google.golang.org/grpc"
"io"
"math/rand"
"time"
"open-match.dev/open-match/examples/demo/components"
"open-match.dev/open-match/internal/rpc"
"open-match.dev/open-match/pkg/pb"
)
@ -65,7 +66,8 @@ func run(ds *components.DemoShared) {
s.Status = "Connecting to backend"
ds.Update(s)
conn, err := rpc.GRPCClientFromConfig(ds.Cfg, "api.backend")
// See https://open-match.dev/site/docs/guides/api/
conn, err := grpc.Dial("om-backend.open-match.svc.cluster.local:50505", grpc.WithInsecure())
if err != nil {
panic(err)
}
@ -80,8 +82,8 @@ func run(ds *components.DemoShared) {
{
req := &pb.FetchMatchesRequest{
Config: &pb.FunctionConfig{
Host: ds.Cfg.GetString("api.functions.hostname"),
Port: int32(ds.Cfg.GetInt("api.functions.grpcport")),
Host: "om-function.open-match.svc.cluster.local",
Port: 50502,
Type: pb.FunctionConfig_GRPC,
},
Profiles: []*pb.MatchProfile{
@ -90,25 +92,27 @@ func run(ds *components.DemoShared) {
Pools: []*pb.Pool{
{
Name: "Everyone",
Filters: []*pb.Filter{
{
Attribute: "mode.demo",
Min: -100,
Max: 100,
},
},
},
},
},
},
}
resp, err := be.FetchMatches(ds.Ctx, req)
stream, err := be.FetchMatches(ds.Ctx, req)
if err != nil {
panic(err)
}
matches = resp.Matches
for {
resp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
matches = append(matches, resp.GetMatch())
}
}
//////////////////////////////////////////////////////////////////////////////

@ -12,44 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package main
// Package demo contains the core startup code for running a demo.
package demo
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
"log"
"net/http"
"golang.org/x/net/websocket"
"open-match.dev/open-match/examples/demo/bytesub"
"open-match.dev/open-match/examples/demo/components"
"open-match.dev/open-match/examples/demo/components/clients"
"open-match.dev/open-match/examples/demo/components/director"
"open-match.dev/open-match/examples/demo/components/uptime"
"open-match.dev/open-match/examples/demo/updater"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/logging"
"open-match.dev/open-match/internal/telemetry"
)
var (
logger = logrus.WithFields(logrus.Fields{
"app": "openmatch",
"component": "examples.demo",
})
)
func main() {
cfg, err := config.Read()
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Fatalf("cannot read configuration.")
}
logging.ConfigureLogging(cfg)
logger.Info("Initializing Server")
// Run starts the provided components, and hosts a webserver for observing the
// output of those components.
func Run(comps map[string]func(*components.DemoShared)) {
log.Print("Initializing Server")
fileServe := http.FileServer(http.Dir("/app/static"))
http.Handle("/static/", http.StripPrefix("/static/", fileServe))
@ -78,25 +62,16 @@ func main() {
bs.Subscribe(ws.Request().Context(), ws)
}))
logger.Info("Starting Server")
log.Print("Starting Server")
go startComponents(cfg, u)
address := fmt.Sprintf(":%d", cfg.GetInt("api.demo.httpport"))
err = http.ListenAndServe(address, nil)
logger.WithError(err).Warning("HTTP server closed.")
}
func startComponents(cfg config.View, u *updater.Updater) {
for name, f := range map[string]func(*components.DemoShared){
"uptime": uptime.Run,
"clients": clients.Run,
"director": director.Run,
} {
for name, f := range comps {
go f(&components.DemoShared{
Ctx: context.Background(),
Cfg: cfg,
Update: u.ForField(name),
})
}
address := fmt.Sprintf(":%d", 51507)
err := http.ListenAndServe(address, nil)
log.Printf("HTTP server closed: %s", err.Error())
}

@ -13,7 +13,11 @@
// limitations under the License.
window.onload = function() {
const ws = new WebSocket("ws://" + window.location.host + "/connect");
let protocol = "ws://";
if (window.location.protocol == "https:") {
protocol = "wss://";
}
const ws = new WebSocket(protocol + window.location.host + "/connect");
ws.onopen = function (event) {
return false;

@ -15,40 +15,99 @@
package evaluate
import (
"open-match.dev/open-match/examples"
"math"
"sort"
"github.com/golang/protobuf/ptypes"
"github.com/sirupsen/logrus"
harness "open-match.dev/open-match/pkg/harness/evaluator/golang"
"open-match.dev/open-match/pkg/pb"
)
type matchInp struct {
match *pb.Match
inp *pb.DefaultEvaluationCriteria
}
// Evaluate is where your custom evaluation logic lives.
// This sample evaluator sorts and deduplicates the input matches.
func Evaluate(p *harness.EvaluatorParams) ([]*pb.Match, error) {
scoreInDescendingOrder := func(a, b *pb.Match) bool {
return a.GetProperties().GetFields()[examples.MatchScore].GetNumberValue() > b.GetProperties().GetFields()[examples.MatchScore].GetNumberValue()
}
by(scoreInDescendingOrder).Sort(p.Matches)
matches := make([]*matchInp, 0, len(p.Matches))
nilEvlautionInputs := 0
results := []*pb.Match{}
dedup := map[string]bool{}
for _, m := range p.Matches {
// Evaluation criteria is optional, but sort it lower than any matches which
// provided criteria.
inp := &pb.DefaultEvaluationCriteria{
Score: math.Inf(-1),
}
for _, match := range p.Matches {
if isNonCollidingMatch(match, dedup) {
for _, ticket := range match.GetTickets() {
dedup[ticket.GetId()] = true
if a, ok := m.Extensions["evaluation_input"]; ok {
err := ptypes.UnmarshalAny(a, inp)
if err != nil {
p.Logger.WithFields(logrus.Fields{
"match_id": m.MatchId,
"error": err,
}).Error("Failed to unmarshal match's DefaultEvaluationCriteria. Rejecting match.")
continue
}
results = append(results, match)
} else {
nilEvlautionInputs++
}
matches = append(matches, &matchInp{
match: m,
inp: inp,
})
}
if nilEvlautionInputs > 0 {
p.Logger.WithFields(logrus.Fields{
"count": nilEvlautionInputs,
}).Info("Some matches don't have the optional field evaluation_input set.")
}
sort.Sort(byScore(matches))
d := decollider{
ticketsUsed: map[string]struct{}{},
}
for _, m := range matches {
d.maybeAdd(m)
}
return d.results, nil
}
type decollider struct {
results []*pb.Match
ticketsUsed map[string]struct{}
}
func (d *decollider) maybeAdd(m *matchInp) {
for _, t := range m.match.GetTickets() {
if _, ok := d.ticketsUsed[t.Id]; ok {
return
}
}
return results, nil
for _, t := range m.match.GetTickets() {
d.ticketsUsed[t.Id] = struct{}{}
}
d.results = append(d.results, m.match)
}
func isNonCollidingMatch(match *pb.Match, validTickets map[string]bool) bool {
for _, ticket := range match.GetTickets() {
id := ticket.GetId()
if _, ok := validTickets[id]; ok {
return false
}
}
return true
type byScore []*matchInp
func (m byScore) Len() int {
return len(m)
}
func (m byScore) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
func (m byScore) Less(i, j int) bool {
return m[i].inp.Score > m[j].inp.Score
}

@ -17,13 +17,22 @@ package evaluate
import (
"testing"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
"github.com/stretchr/testify/assert"
"open-match.dev/open-match/examples"
harness "open-match.dev/open-match/pkg/harness/evaluator/golang"
"open-match.dev/open-match/pkg/pb"
"open-match.dev/open-match/pkg/structs"
)
func mustAny(m proto.Message) *any.Any {
result, err := ptypes.MarshalAny(m)
if err != nil {
panic(err)
}
return result
}
func TestEvaluate(t *testing.T) {
ticket1 := &pb.Ticket{Id: "1"}
ticket2 := &pb.Ticket{Id: "2"}
@ -31,30 +40,38 @@ func TestEvaluate(t *testing.T) {
ticket12Score1 := &pb.Match{
Tickets: []*pb.Ticket{ticket1, ticket2},
Properties: structs.Struct{
examples.MatchScore: structs.Number(1),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": mustAny(&pb.DefaultEvaluationCriteria{
Score: 1,
}),
},
}
ticket12Score10 := &pb.Match{
Tickets: []*pb.Ticket{ticket2, ticket1},
Properties: structs.Struct{
examples.MatchScore: structs.Number(10),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": mustAny(&pb.DefaultEvaluationCriteria{
Score: 10,
}),
},
}
ticket123Score5 := &pb.Match{
Tickets: []*pb.Ticket{ticket1, ticket2, ticket3},
Properties: structs.Struct{
examples.MatchScore: structs.Number(5),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": mustAny(&pb.DefaultEvaluationCriteria{
Score: 5,
}),
},
}
ticket3Score50 := &pb.Match{
Tickets: []*pb.Ticket{ticket3},
Properties: structs.Struct{
examples.MatchScore: structs.Number(50),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": mustAny(&pb.DefaultEvaluationCriteria{
Score: 50,
}),
},
}
tests := []struct {

@ -1,53 +0,0 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package evaluate
import (
"sort"
"open-match.dev/open-match/pkg/pb"
)
// by is the type of a "less" function that defines the ordering of its Planet arguments.
type by func(p1, p2 *pb.Match) bool
// matchSorter joins a By function and a slice of Matches to be sorted.
type matchSorter struct {
matches []*pb.Match
by func(a, b *pb.Match) bool // Closure used in the Less method.
}
// Sort is a method on the function type, By, that sorts the argument slice according to the function.
func (by by) Sort(matches []*pb.Match) {
sort.Sort(&matchSorter{
matches: matches,
by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
})
}
// Len is part of sort.Interface.
func (s *matchSorter) Len() int {
return len(s.matches)
}
// Swap is part of sort.Interface.
func (s *matchSorter) Swap(i, j int) {
s.matches[i], s.matches[j] = s.matches[j], s.matches[i]
}
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *matchSorter) Less(i, j int) bool {
return s.by(s.matches[i], s.matches[j])
}

@ -20,11 +20,12 @@
package mmf
import (
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
"github.com/pkg/errors"
"github.com/rs/xid"
"open-match.dev/open-match/examples"
mmfHarness "open-match.dev/open-match/pkg/harness/function/golang"
"open-match.dev/open-match/pkg/pb"
"open-match.dev/open-match/pkg/structs"
)
var (
@ -46,15 +47,22 @@ func MakeMatches(params *mmfHarness.MatchFunctionParams) ([]*pb.Match, error) {
roster.TicketIds = append(roster.GetTicketIds(), ticket.GetId())
}
evaluationInput, err := ptypes.MarshalAny(&pb.DefaultEvaluationCriteria{
Score: scoreCalculator(tickets),
})
if err != nil {
return nil, errors.Wrap(err, "Failed to marshal DefaultEvaluationCriteria.")
}
result = append(result, &pb.Match{
MatchId: xid.New().String(),
MatchProfile: params.ProfileName,
MatchFunction: matchName,
Tickets: tickets,
Rosters: []*pb.Roster{roster},
Properties: structs.Struct{
examples.MatchScore: structs.Number(scoreCalculator(tickets)),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": evaluationInput,
},
})
}
}
@ -62,12 +70,14 @@ func MakeMatches(params *mmfHarness.MatchFunctionParams) ([]*pb.Match, error) {
return result, nil
}
// This match function defines the quality of a match as the sum of the attribute values of all tickets per match
// This match function defines the quality of a match as the sum of the Double
// Args values of all tickets per match. This is for testing purposes, and not
// an example of a good score calculation.
func scoreCalculator(tickets []*pb.Ticket) float64 {
matchScore := 0.0
for _, ticket := range tickets {
for _, v := range ticket.GetProperties().GetFields() {
matchScore += v.GetNumberValue()
for _, v := range ticket.GetSearchFields().GetDoubleArgs() {
matchScore += v
}
}
return matchScore

@ -17,13 +17,13 @@ package mmf
import (
"testing"
"open-match.dev/open-match/examples"
"open-match.dev/open-match/pkg/pb"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
mmfHarness "open-match.dev/open-match/pkg/harness/function/golang"
"open-match.dev/open-match/pkg/structs"
)
func TestMakeMatches(t *testing.T) {
@ -32,30 +32,38 @@ func TestMakeMatches(t *testing.T) {
tickets := []*pb.Ticket{
{
Id: "1",
Properties: structs.Struct{
"level": structs.Number(10),
"defense": structs.Number(100),
}.S(),
SearchFields: &pb.SearchFields{
DoubleArgs: map[string]float64{
"level": 10,
"defense": 100,
},
},
},
{
Id: "2",
Properties: structs.Struct{
"level": structs.Number(10),
"attack": structs.Number(50),
}.S(),
SearchFields: &pb.SearchFields{
DoubleArgs: map[string]float64{
"level": 10,
"defense": 50,
},
},
},
{
Id: "3",
Properties: structs.Struct{
"level": structs.Number(10),
"speed": structs.Number(522),
}.S(),
SearchFields: &pb.SearchFields{
DoubleArgs: map[string]float64{
"level": 10,
"defense": 522,
},
},
}, {
Id: "4",
Properties: structs.Struct{
"level": structs.Number(10),
"mana": structs.Number(1),
}.S(),
SearchFields: &pb.SearchFields{
DoubleArgs: map[string]float64{
"level": 10,
"mana": 1,
},
},
},
}
@ -82,7 +90,7 @@ func TestMakeMatches(t *testing.T) {
MatchFunction: match.MatchFunction,
Tickets: match.Tickets,
Rosters: match.Rosters,
Properties: match.Properties,
Extensions: match.Extensions,
})
}
@ -92,14 +100,21 @@ func TestMakeMatches(t *testing.T) {
tids = append(tids, ticket.GetId())
}
evaluationInput, err := ptypes.MarshalAny(&pb.DefaultEvaluationCriteria{
Score: scoreCalculator(tickets),
})
if err != nil {
t.Fatal(err)
}
return &pb.Match{
MatchProfile: p.ProfileName,
MatchFunction: matchName,
Tickets: tickets,
Rosters: []*pb.Roster{{Name: poolName, TicketIds: tids}},
Properties: structs.Struct{
examples.MatchScore: structs.Number(scoreCalculator(tickets)),
}.S(),
Extensions: map[string]*any.Any{
"evaluation_input": evaluationInput,
},
}
}

@ -14,12 +14,11 @@
FROM open-match-base-build as builder
WORKDIR /go/src/open-match.dev/open-match/examples/demo
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o demo .
WORKDIR /go/src/open-match.dev/open-match/examples/functions/golang/rosterbased
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o matchfunction .
FROM gcr.io/distroless/static:nonroot
WORKDIR /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/examples/demo/demo /app/
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/examples/demo/static /app/static
COPY --from=builder --chown=nonroot /go/src/open-match.dev/open-match/examples/functions/golang/rosterbased/matchfunction /app/
ENTRYPOINT ["/app/demo"]
ENTRYPOINT ["/app/matchfunction"]

@ -0,0 +1,34 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package main defines a sample match function that uses the GRPC harness to set up
// the match making function as a service. This sample is a reference
// to demonstrate the usage of the GRPC harness and should only be used as
// a starting point for your match function. You will need to modify the
// matchmaking logic in this function based on your game's requirements.
package main
import (
"open-match.dev/open-match/examples/functions/golang/rosterbased/mmf"
)
var (
// Replace these values with the approriate values for your Open Match setup.
mmlogicAddress = "om-mmlogic.open-match.svc.cluster.local:50503" // Address of the MMLogic Endpoint.
serverPort = 50502 // Port of the server where the match function is hosted.
)
func main() {
mmf.Start(mmlogicAddress, serverPort)
}

@ -0,0 +1,151 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mmf
import (
"fmt"
"time"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"open-match.dev/open-match/pkg/matchfunction"
"open-match.dev/open-match/pkg/pb"
)
var (
matchName = "roster-based-matchfunction"
emptyRosterSpot = "EMPTY_ROSTER_SPOT"
logger = logrus.WithFields(logrus.Fields{
"app": "matchfunction",
"component": "mmf.rosterbased",
})
)
// Run is this match function's implementation of the gRPC call defined in api/matchfunction.proto.
func (s *MatchFunctionService) Run(req *pb.RunRequest, stream pb.MatchFunction_RunServer) error {
// Fetch tickets for the pools specified in the Match Profile.
poolTickets, err := matchfunction.QueryPools(stream.Context(), s.mmlogicClient, req.GetProfile().GetPools())
if err != nil {
return err
}
// Generate proposals.
proposals, err := makeMatches(req.GetProfile(), poolTickets)
if err != nil {
return err
}
logger.WithFields(logrus.Fields{
"proposals": proposals,
}).Trace("proposals returned by match function")
// Stream the generated proposals back to Open Match.
for _, proposal := range proposals {
if err := stream.Send(&pb.RunResponse{Proposal: proposal}); err != nil {
return err
}
}
return nil
}
func makeMatches(p *pb.MatchProfile, poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error) {
// This roster based match function expects the match profile to have a
// populated roster specifying the empty slots for each pool name and also
// have the ticket pools referenced in the roster. It generates matches by
// populating players from the specified pools into rosters.
wantTickets, err := wantPoolTickets(p.Rosters)
if err != nil {
return nil, err
}
var matches []*pb.Match
count := 0
for {
insufficientTickets := false
matchTickets := []*pb.Ticket{}
matchRosters := []*pb.Roster{}
// Loop through each pool wanted in the rosters and pick the number of
// wanted players from the respective Pool.
for poolName, want := range wantTickets {
have, ok := poolTickets[poolName]
if !ok {
// A wanted Pool was not found in the Pools specified in the profile.
insufficientTickets = true
break
}
if len(have) < want {
// The Pool in the profile has fewer tickets than what the roster needs.
insufficientTickets = true
break
}
// Populate the wanted tickets from the Tickets in the corresponding Pool.
matchTickets = append(matchTickets, have[0:want]...)
poolTickets[poolName] = have[want:]
var ids []string
for _, ticket := range matchTickets {
ids = append(ids, ticket.Id)
}
matchRosters = append(matchRosters, &pb.Roster{
Name: poolName,
TicketIds: ids,
})
}
if insufficientTickets {
// Ran out of Tickets. Matches cannot be created from the remaining Tickets.
break
}
matches = append(matches, &pb.Match{
MatchId: fmt.Sprintf("profile-%v-time-%v-%v", p.GetName(), time.Now().Format("2006-01-02T15:04:05.00"), count),
MatchProfile: p.GetName(),
MatchFunction: matchName,
Tickets: matchTickets,
Rosters: matchRosters,
})
count++
}
return matches, nil
}
// wantPoolTickets parses the roster to return a map of the Pool name to the
// number of empty roster slots for that Pool.
func wantPoolTickets(rosters []*pb.Roster) (map[string]int, error) {
wantTickets := make(map[string]int)
for _, r := range rosters {
if _, ok := wantTickets[r.Name]; ok {
// We do not expect multiple Roster Pools to have the same name.
logger.Errorf("multiple rosters with same name not supported")
return nil, status.Error(codes.InvalidArgument, "multiple rosters with same name not supported")
}
wantTickets[r.Name] = 0
for _, slot := range r.TicketIds {
if slot == emptyRosterSpot {
wantTickets[r.Name] = wantTickets[r.Name] + 1
}
}
}
return wantTickets, nil
}

@ -0,0 +1,73 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mmf
import (
"fmt"
"net"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"open-match.dev/open-match/pkg/pb"
)
// matchFunctionService implements pb.MatchFunctionServer, the server generated
// by compiling the protobuf, by fulfilling the pb.MatchFunctionServer interface.
type MatchFunctionService struct {
grpc *grpc.Server
mmlogicClient pb.MmLogicClient
port int
}
// Start creates and starts the Match Function server and also connects to Open
// Match's mmlogic service. This connection is used at runtime to fetch tickets
// for pools specified in MatchProfile.
func Start(mmlogicAddr string, serverPort int) error {
conn, err := grpc.Dial(mmlogicAddr, grpc.WithInsecure())
if err != nil {
logger.Fatalf("Failed to connect to Open Match, got %v", err)
}
defer conn.Close()
mmfService := MatchFunctionService{
mmlogicClient: pb.NewMmLogicClient(conn),
}
server := grpc.NewServer()
pb.RegisterMatchFunctionServer(server, &mmfService)
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", serverPort))
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
"port": serverPort,
}).Error("net.Listen() error")
return err
}
logger.WithFields(logrus.Fields{
"port": serverPort,
}).Info("TCP net listener initialized")
logger.Info("Serving gRPC endpoint")
err = server.Serve(ln)
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Error("gRPC serve() error")
return err
}
return nil
}

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: om-evaluator
namespace: open-match
spec:
containers:
- name: om-evaluator
image: "gcr.io/open-match-build/openmatch-evaluator-go-simple"
imagePullPolicy: Always
ports:
- name: grpc
containerPort: 50508
- name: http
containerPort: 51508
hostname: om-evaluator

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: om-function
namespace: open-match
spec:
containers:
- name: om-function
image: "gcr.io/open-match-build/openmatch-mmf-go-soloduel"
imagePullPolicy: Always
ports:
- name: grpc
containerPort: 50502
- name: http
containerPort: 51502
hostname: om-function

@ -0,0 +1,183 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package backend
import (
"context"
"fmt"
"io"
"math/rand"
"sync"
"sync/atomic"
"time"
"github.com/sirupsen/logrus"
"open-match.dev/open-match/examples/scale/profiles"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/logging"
"open-match.dev/open-match/internal/rpc"
"open-match.dev/open-match/pkg/pb"
)
var (
logger = logrus.WithFields(logrus.Fields{
"app": "openmatch",
"component": "scale.backend",
})
// TODO: Add metrics to track matches created, tickets assigned, deleted.
matchCount uint64
assigned uint64
deleted uint64
)
// Run triggers execution of functions that continuously fetch, assign and
// delete matches.
func Run() {
cfg, err := config.Read()
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Fatalf("cannot read configuration.")
}
logging.ConfigureLogging(cfg)
beConn, err := rpc.GRPCClientFromConfig(cfg, "api.backend")
if err != nil {
logger.Fatalf("failed to connect to Open Match Backend, got %v", err)
}
defer beConn.Close()
be := pb.NewBackendClient(beConn)
feConn, err := rpc.GRPCClientFromConfig(cfg, "api.frontend")
if err != nil {
logger.Fatalf("failed to connect to Open Match Frontend, got %v", err)
}
defer feConn.Close()
fe := pb.NewFrontendClient(feConn)
// The buffered channels attempt to decouple fetch, assign and delete. It is
// best effort and these operations may still block each other if buffers are full.
matches := make(chan *pb.Match, 1000)
deleteIds := make(chan string, 1000)
go doFetch(cfg, be, matches)
go doAssign(be, matches, deleteIds)
go doDelete(fe, deleteIds)
// The above goroutines run forever and so the main goroutine needs to block.
select {}
}
// doFetch continuously fetches all profiles in a loop and queues up the fetched
// matches for assignment.
func doFetch(cfg config.View, be pb.BackendClient, matches chan *pb.Match) {
startTime := time.Now()
mprofiles := profiles.Generate(cfg)
for {
var wg sync.WaitGroup
for _, p := range mprofiles {
wg.Add(1)
p := p
go func(wg *sync.WaitGroup) {
defer wg.Done()
fetch(be, p, matches)
}(&wg)
}
// Wait for all FetchMatches calls to complete before proceeding.
wg.Wait()
logger.Infof("FetchedMatches:%v, AssignedTickets:%v, DeletedTickets:%v in time %v", atomic.LoadUint64(&matchCount), atomic.LoadUint64(&assigned), atomic.LoadUint64(&deleted), time.Since(startTime))
}
}
func fetch(be pb.BackendClient, p *pb.MatchProfile, matches chan *pb.Match) {
req := &pb.FetchMatchesRequest{
Config: &pb.FunctionConfig{
Host: "om-function",
Port: 50502,
Type: pb.FunctionConfig_GRPC,
},
Profiles: []*pb.MatchProfile{p},
}
stream, err := be.FetchMatches(context.Background(), req)
if err != nil {
logger.Errorf("FetchMatches failed, got %v", err)
return
}
for {
resp, err := stream.Recv()
if err == io.EOF {
return
}
if err != nil {
logger.Errorf("FetchMatches failed, got %v", err)
return
}
matches <- resp.GetMatch()
atomic.AddUint64(&matchCount, 1)
}
}
// doAssign continuously assigns matches that were queued in the matches channel
// by doFetch and after successful assignment, queues all the tickets to deleteIds
// channel for deletion by doDelete.
func doAssign(be pb.BackendClient, matches chan *pb.Match, deleteIds chan string) {
for match := range matches {
ids := []string{}
for _, t := range match.Tickets {
ids = append(ids, t.Id)
}
req := &pb.AssignTicketsRequest{
TicketIds: ids,
Assignment: &pb.Assignment{
Connection: fmt.Sprintf("%d.%d.%d.%d:2222", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)),
},
}
if _, err := be.AssignTickets(context.Background(), req); err != nil {
logger.Errorf("AssignTickets failed, got %v", err)
continue
}
atomic.AddUint64(&assigned, uint64(len(ids)))
for _, id := range ids {
deleteIds <- id
}
}
}
// doDelete deletes all the tickets whose ids get added to the deleteIds channel.
func doDelete(fe pb.FrontendClient, deleteIds chan string) {
for id := range deleteIds {
req := &pb.DeleteTicketRequest{
TicketId: id,
}
if _, err := fe.DeleteTicket(context.Background(), req); err != nil {
logger.Errorf("DeleteTicket failed for ticket %v, got %v", id, err)
continue
}
atomic.AddUint64(&deleted, 1)
}
}

@ -0,0 +1,93 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package frontend
import (
"context"
"sync"
"sync/atomic"
"time"
"github.com/sirupsen/logrus"
"open-match.dev/open-match/examples/scale/tickets"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/logging"
"open-match.dev/open-match/internal/rpc"
"open-match.dev/open-match/pkg/pb"
)
var (
logger = logrus.WithFields(logrus.Fields{
"app": "openmatch",
"component": "scale.frontend",
})
)
// Run triggers execution of the scale frontend component that creates
// tickets at scale in Open Match.
func Run() {
cfg, err := config.Read()
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Fatal("cannot read configuration.")
}
logging.ConfigureLogging(cfg)
doCreate(cfg)
}
func doCreate(cfg config.View) {
concurrent := cfg.GetInt("testConfig.concurrent-creates")
conn, err := rpc.GRPCClientFromConfig(cfg, "api.frontend")
if err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Fatal("failed to get Frontend connection")
}
defer conn.Close()
fe := pb.NewFrontendClient(conn)
var created uint64
var failed uint64
start := time.Now()
for {
var wg sync.WaitGroup
for i := 0; i <= concurrent; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup) {
defer wg.Done()
req := &pb.CreateTicketRequest{
Ticket: tickets.Ticket(cfg),
}
if _, err := fe.CreateTicket(context.Background(), req); err != nil {
logger.WithFields(logrus.Fields{
"error": err.Error(),
}).Error("failed to create a ticket.")
atomic.AddUint64(&failed, 1)
return
}
atomic.AddUint64(&created, 1)
}(&wg)
}
// Wait for all concurrent creates to complete.
wg.Wait()
logger.Infof("%v tickets created, %v failed in %v", created, failed, time.Since(start))
}
}

@ -0,0 +1,47 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profiles
import (
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/testing/e2e"
"open-match.dev/open-match/pkg/pb"
)
// greedyProfiles generates a single profile that has only one Pool that has a single
// filter which covers the entire range of player ranks, thereby pulling in the entire
// player population during each profile execution.
func greedyProfiles(cfg config.View) []*pb.MatchProfile {
return []*pb.MatchProfile{
{
Name: "greedy",
Pools: []*pb.Pool{
{
Name: "all",
DoubleRangeFilters: []*pb.DoubleRangeFilter{
{
DoubleArg: e2e.DoubleArgMMR,
Min: float64(cfg.GetInt("testConfig.minRating")),
Max: float64(cfg.GetInt("testConfig.maxRating")),
},
},
},
},
Rosters: []*pb.Roster{
makeRosterSlots("all", cfg.GetInt("testConfig.ticketsPerMatch")),
},
},
}
}

@ -0,0 +1,81 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profiles
import (
"fmt"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/testing/e2e"
"open-match.dev/open-match/pkg/pb"
)
// multifilterProfiles generates a multiple profiles, each containing a single Pool
// that specifies multiple filters to pick a partitioned player population. Note
// that across all the profiles returned, the entire population is covered and given
// the overlapping nature of filters, multiple profiles returned by this method may
// match to the same set of players.
func multifilterProfiles(cfg config.View) []*pb.MatchProfile {
regions := cfg.GetStringSlice("testConfig.regions")
ratingFilters := makeRangeFilters(&rangeConfig{
name: "Rating",
min: cfg.GetInt("testConfig.minRating"),
max: cfg.GetInt("testConfig.maxRating"),
rangeSize: cfg.GetInt("testConfig.multifilter.rangeSize"),
rangeOverlap: cfg.GetInt("testConfig.multifilter.rangeOverlap"),
})
latencyFilters := makeRangeFilters(&rangeConfig{
name: "Latency",
min: 0,
max: 100,
rangeSize: 70,
rangeOverlap: 0,
})
var profiles []*pb.MatchProfile
for _, region := range regions {
for _, latency := range latencyFilters {
for _, rating := range ratingFilters {
poolName := fmt.Sprintf("%s_%s_%s", region, rating.name, latency.name)
p := &pb.Pool{
Name: poolName,
DoubleRangeFilters: []*pb.DoubleRangeFilter{
{
DoubleArg: e2e.DoubleArgMMR,
Min: float64(rating.min),
Max: float64(rating.max),
},
{
DoubleArg: region,
Min: float64(latency.min),
Max: float64(latency.max),
},
},
}
prof := &pb.MatchProfile{
Name: fmt.Sprintf("Profile_%s", poolName),
Pools: []*pb.Pool{p},
Rosters: []*pb.Roster{makeRosterSlots(p.GetName(), cfg.GetInt("testConfig.ticketsPerMatch"))},
}
profiles = append(profiles, prof)
}
}
}
return profiles
}

@ -0,0 +1,94 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profiles
import (
"fmt"
"math"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/internal/testing/e2e"
"open-match.dev/open-match/pkg/pb"
)
// multipoolProfiles generates a multiple profiles, each containing a multiple player
// Pools specifying multiple filters each. The profile also requests a roster of a
// configured number of players per pool to be placed in a match.
func multipoolProfiles(cfg config.View) []*pb.MatchProfile {
characters := cfg.GetStringSlice("testConfig.characters")
regions := cfg.GetStringSlice("testConfig.regions")
ratingFilters := makeRangeFilters(&rangeConfig{
name: "Rating",
min: cfg.GetInt("testConfig.minRating"),
max: cfg.GetInt("testConfig.maxRating"),
rangeSize: cfg.GetInt("testConfig.multipool.rangeSize"),
rangeOverlap: cfg.GetInt("testConfig.multipool.rangeOverlap"),
})
latencyFilters := makeRangeFilters(&rangeConfig{
name: "Latency",
min: 0,
max: 100,
rangeSize: 70,
rangeOverlap: 0,
})
var profiles []*pb.MatchProfile
for _, region := range regions {
for _, latency := range latencyFilters {
for _, rating := range ratingFilters {
var pools []*pb.Pool
var rosters []*pb.Roster
for _, character := range characters {
poolName := fmt.Sprintf("%s_%s_%s_%s", region, rating.name, latency.name, character)
p := &pb.Pool{
Name: poolName,
DoubleRangeFilters: []*pb.DoubleRangeFilter{
// TODO: Use StringEqualsFilter for the character args.
{
DoubleArg: character,
Min: 0,
Max: math.MaxFloat64,
},
{
DoubleArg: e2e.DoubleArgMMR,
Min: float64(rating.min),
Max: float64(rating.max),
},
{
DoubleArg: region,
Min: float64(latency.min),
Max: float64(latency.max),
},
},
}
rosters = append(rosters, makeRosterSlots(poolName, cfg.GetInt("testConfig.multipool.characterCount")))
pools = append(pools, p)
}
prof := &pb.MatchProfile{
Name: fmt.Sprintf("Profile_%s", fmt.Sprintf("%s_%s_%s", region, rating.name, latency.name)),
Pools: pools,
Rosters: rosters,
}
profiles = append(profiles, prof)
}
}
}
return profiles
}

@ -0,0 +1,53 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profiles
import (
"github.com/sirupsen/logrus"
"open-match.dev/open-match/internal/config"
"open-match.dev/open-match/pkg/pb"
)
var (
logger = logrus.WithFields(logrus.Fields{
"app": "openmatch",
"component": "scale.profiles",
})
// Greedy config type is used to pick profiles that pull in all players.
Greedy = "greedy"
// MultiFilter config type is used to pick profiles that have a Pool that uses multiple filters.
MultiFilter = "multifilter"
// MultiPool config type is used to pick profiles that have multiple Pools with multiple filters each.
MultiPool = "multipool"
// emptyRosterSpot is the string that represents an empty slot on a Roster.
emptyRosterSpot = "EMPTY_ROSTER_SPOT"
)
// Generate generates test profiles for scale demo
func Generate(cfg config.View) []*pb.MatchProfile {
profile := cfg.GetString("testConfig.profile")
switch profile {
case Greedy:
return greedyProfiles(cfg)
case MultiFilter:
return multifilterProfiles(cfg)
case MultiPool:
return multipoolProfiles(cfg)
}
logger.Warningf("Unexpected profile name %s, not returning any profiles", profile)
return nil
}

@ -0,0 +1,72 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profiles
import (
"fmt"
"open-match.dev/open-match/pkg/pb"
)
type rangeFilter struct {
name string
min int
max int
}
type rangeConfig struct {
name string
min int
max int
rangeSize int
rangeOverlap int
}
// makeRosterSlots generates a roster with the specified name and with the
// specified number of empty roster slots.
func makeRosterSlots(name string, count int) *pb.Roster {
roster := &pb.Roster{
Name: name,
}
for i := 0; i <= count; i++ {
roster.TicketIds = append(roster.TicketIds, emptyRosterSpot)
}
return roster
}
// makeRangeFilters generates multiple filters over a given range based on
// the size of the range and the overlap specified for the filters.
func makeRangeFilters(config *rangeConfig) []*rangeFilter {
var filters []*rangeFilter
r := config.min
for r <= config.max {
max := r + config.rangeSize
if max > config.max {
r = config.max
}
filters = append(filters, &rangeFilter{
name: fmt.Sprintf("%s_%dto%d", config.name, r, max),
min: r,
max: max,
})
r = r + 1 + (config.rangeSize - config.rangeOverlap)
}
return filters
}

@ -0,0 +1,83 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tickets
import (
"math/rand"
"open-match.dev/open-match/internal/config"
"github.com/sirupsen/logrus"
"open-match.dev/open-match/internal/testing/e2e"
"open-match.dev/open-match/pkg/pb"
)
var (
logger = logrus.WithFields(logrus.Fields{
"app": "openmatch",
"component": "scale.tickets",
})
)
// Ticket generates a ticket based on the config for scale testing
func Ticket(cfg config.View) *pb.Ticket {
characters := cfg.GetStringSlice("testConfig.characters")
regions := cfg.GetStringSlice("testConfig.regions")
min := cfg.GetFloat64("testConfig.minRating")
max := cfg.GetFloat64("testConfig.maxRating")
latencyMap := latency(regions)
ticket := &pb.Ticket{
SearchFields: &pb.SearchFields{
DoubleArgs: map[string]float64{
e2e.DoubleArgMMR: normalDist(40, min, max, 20),
},
StringArgs: map[string]string{
e2e.Role: characters[rand.Intn(len(characters))],
},
},
}
for _, r := range regions {
ticket.SearchFields.DoubleArgs[r] = latencyMap[r]
}
return ticket
}
// latency generates a latency mapping of each region to a latency value. It picks
// one region with latency between 0ms to 100ms and sets latencies to all other regions
// to a value between 100ms to 300ms.
func latency(regions []string) map[string]float64 {
latencies := make(map[string]float64)
for _, r := range regions {
latencies[r] = normalDist(175, 100, 300, 75)
}
latencies[regions[rand.Intn(len(regions))]] = normalDist(25, 0, 100, 75)
return latencies
}
// normalDist generates a random integer in a normal distribution
func normalDist(avg float64, min float64, max float64, stdev float64) float64 {
sample := (rand.NormFloat64() * stdev) + avg
switch {
case sample > max:
sample = max
case sample < min:
sample = min
}
return sample
}

25
go.mod

@ -14,10 +14,11 @@ module open-match.dev/open-match
// See the License for the specific language governing permissions and
// limitations under the License.
go 1.12
// When updating Go version, update Dockerfile.ci, Dockerfile.base-build, and go.mod
go 1.13.1
require (
cloud.google.com/go v0.40.0
cloud.google.com/go v0.40.0 // indirect
contrib.go.opencensus.io/exporter/jaeger v0.1.0
contrib.go.opencensus.io/exporter/ocagent v0.5.0
contrib.go.opencensus.io/exporter/prometheus v0.1.0
@ -27,26 +28,30 @@ require (
github.com/alicebob/miniredis/v2 v2.8.1-0.20190618082157-e29950035715
github.com/cenkalti/backoff v2.1.1+incompatible
github.com/fsnotify/fsnotify v1.4.7
github.com/go-logfmt/logfmt v0.4.0 // indirect
github.com/gogo/protobuf v1.2.1
github.com/golang/protobuf v1.3.1
github.com/gogo/protobuf v1.3.0 // indirect
github.com/golang/protobuf v1.3.2
github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3
github.com/google/gofuzz v1.0.0 // indirect
github.com/googleapis/gnostic v0.3.1 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
github.com/grpc-ecosystem/grpc-gateway v1.9.2
github.com/grpc-ecosystem/grpc-gateway v1.9.6
github.com/imdario/mergo v0.3.7 // indirect
github.com/openzipkin/zipkin-go v0.1.6
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.0.0
github.com/rs/xid v1.2.1
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.3.0
go.opencensus.io v0.22.0
golang.org/x/net v0.0.0-20190522155817-f3200d17e092
google.golang.org/genproto v0.0.0-20190611190212-a7e196e89fd3
google.golang.org/grpc v1.21.1
k8s.io/api v0.0.0-20190624085159-95846d7ef82a
k8s.io/apimachinery v0.0.0-20190624085041-961b39a1baa0
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.0.0-20190708094356-59223ed9f6ce // kubernetes-1.12.10
k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc // kubernetes-1.12.10
k8s.io/client-go v9.0.0+incompatible // kubernetes-1.12.10
)

75
go.sum

@ -14,7 +14,6 @@ contrib.go.opencensus.io/exporter/stackdriver v0.12.2/go.mod h1:iwB6wGarfphGGe/e
contrib.go.opencensus.io/exporter/zipkin v0.1.1 h1:PR+1zWqY8ceXs1qDQQIlgXe+sdiwCf0n32bH4+Epk8g=
contrib.go.opencensus.io/exporter/zipkin v0.1.1/go.mod h1:GMvdSl3eJ2gapOaLKzTKE3qDgUkJ86k9k3yY2eqwkzc=
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -53,16 +52,12 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@ -72,72 +67,69 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3 h1:6amM4HsNPOvMLVc2ZnyqrjeQ92YAVWn7T4WBKK87inY=
github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.2 h1:S+ef0492XaIknb8LMjcwgW2i3cNTzDYMmDrOThOJNWc=
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.6 h1:8p0pcgLlw2iuZVsdHdPaMUXFOA+6gDixcXbHEMzSyW8=
github.com/grpc-ecosystem/grpc-gateway v1.9.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -158,18 +150,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -209,7 +198,6 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@ -217,7 +205,6 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
@ -242,7 +229,6 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -259,10 +245,8 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
@ -286,23 +270,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -337,8 +319,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@ -349,21 +331,10 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/api v0.0.0-20190624085159-95846d7ef82a h1:j1H0i/hUVkDK9Y0xFEc0pQpnyuJNxvdhfy5Vj2MGCXA=
k8s.io/api v0.0.0-20190624085159-95846d7ef82a/go.mod h1:O6YAz5STgv7S1/c/XtBULGhSltH7yWEHpWvnA1mmFRg=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
k8s.io/apimachinery v0.0.0-20190624085041-961b39a1baa0 h1:7oql7STcnJ85hz3BIbasXHH/+lLLKwOdsG8vjkZc8Pc=
k8s.io/apimachinery v0.0.0-20190624085041-961b39a1baa0/go.mod h1:48PVecD7ubRgJmMRGIQfsqYu6OucVH5DzFNtACHZH8k=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a h1:2jUDc9gJja832Ftp+QbDV0tVhQHMISFn01els+2ZAcw=
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/api v0.0.0-20190708094356-59223ed9f6ce h1:5dyrqZX6sr+cG/e26KF2p6GuTIABBACjjGSOSdjS9sI=
k8s.io/api v0.0.0-20190708094356-59223ed9f6ce/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc h1:7z9/6jKWBqkK9GI1RRB0B5fZcmkatLQ/nv8kysch24o=
k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/client-go v9.0.0+incompatible h1:2kqW3X2xQ9SbFvWZjGEHBLlWc1LG9JIJNXWkuqwdZ3A=
k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

@ -0,0 +1,29 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: gce:podsecuritypolicy:gke-metadata-server-workaround
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gce:podsecuritypolicy:privileged
subjects:
- kind: ServiceAccount
name: gke-metadata-server
namespace: kube-system

@ -1,24 +1,69 @@
Open Match Helm Chart
=====================
### Open Match Helm Chart Templates
This directory contains the [helm](https://helm.sh/ "helm") chart templates used to customize and deploy Open Match.
Open Match provides a Helm chart to quickly
Templates under the `templates/` directory are for the core components in Open Match - e.g. backend, frontend, mmlogic, synchronizor, some security policies, and configmaps are defined under this folder.
```bash
# Install Helm and Tiller
# See https://github.com/helm/helm/releases for
cd /tmp && curl -Lo helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.13.0-linux-amd64.tar.gz && tar xvzf helm.tar.gz --strip-components 1 && mv helm $(PREFIX)/bin/helm && mv tiller $(PREFIX)/bin/tiller
Open Match also provides templates for optional components that are disabled by default under the `subcharts/` directory.
1. `open-match-demo` contains the template for a sample director.
2. `open-match-customize` contains flexible templates to deploy your own matchfunction and evaluator.
3. `open-match-telemetry` contains monitoring supports for Open Match, you may choose to enable/disable [jaeger](https://www.jaegertracing.io/ "jaeger"), [prometheus](http://prometheus.io "prometheus"), [stackdriver](https://cloud.google.com/stackdriver/ "stackdriver"), [zipkin](https://zipkin.io/ "zipkin"), and [grafana](https://grafana.com/ "grafana") by overriding the config values in the provided templates.
4. `open-match-test` contains templates of the end-to-end in-cluster tests and distributed stress tests for Open Match.
# Install Helm to Kubernetes Cluster
kubectl create serviceaccount --namespace kube-system tiller
helm init --service-account tiller --force-upgrade
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
# Run if RBAC is enabled.
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
You may control the behavior of Open Match by overriding the configs in `install/helm/open-match/values.yaml` file. Here are a few examples:
# Deploy Open Match
helm upgrade --install --wait --debug open-match \
install/helm/open-match \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
```diff
# install/helm/open-match/values.yaml
# 1. Configs under the `global` section affects all components - including components in the subcharts.
# 2. Configs under the subchart name - e.g. `open-match-test` only affects the settings in that subchart.
# 3. Otherwise, the configs are for core components (templates in the parent chart) only.
# Overrides spec.type of a specific Kubernetes Service
# Equivalent helm cli flag --set swaggerui.portType=LoadBalancer
swaggerui:
- portType: ClusterIP
+ portType: LoadBalancer
# Overrides spec.type of all Open Match components - including components in the subcharts
# Equivalent helm cli flag --set global.kubernetes.service.portType=LoadBalancer
global:
kubernetes:
service:
- portType: ClusterIP
+ portType: LoadBalancer
# Enables grafana support in Open Match
# Equivalent helm cli flag --set global.telemetry.grafana.enabled=true
global:
telemetry:
grafana:
- enabled: false
+ enabled: true
# Enables an optional component in Open Match
# Equivalent helm cli flag --set open-match-demo.enabled=true
open-match-demo:
- enabled: false
+ enabled: true
# Enables rpc logging in Open Match
# Equivalent helm cli flag --set global.logging.rpc.enabled=true
global:
logging:
rpc:
- enabled: false
+ enabled: true
# Instructs Open Match to use customized matchfunction and evaluator images
# Equivalent helm cli flag --set open-match-customize.image.registry=[XXX],open-match-customize.image.tag=[XXX]
open-match-customize:
enabled: true
+ image:
+ registry: [YOUR_REGISTRY_URL]
+ tag: [YOUR_IMAGE_TAG]
+ function:
+ image: [YOUR_MATCHFUNCTION_IMAGE_NAME]
+ evaluator:
+ image: [YOUR_EVALUATOR_IMAGE_NAME]
```
Please see [Helm - Chart Template Guide](https://helm.sh/docs/chart_template_guide/#the-chart-template-developer-s-guide "Chart Template Guide") for the advanced usages and our [Makefile](https://github.com/googleforgames/open-match/blob/master/Makefile#L358 "Makefile") for how we use the helm charts to deploy Open Match.

@ -13,8 +13,8 @@
# limitations under the License.
apiVersion: v1
appVersion: "0.6.0"
version: 0.6.0
appVersion: "0.8.0-rc.1"
version: 0.8.0-rc.1
name: open-match
description: Flexible, extensible, and scalable video game matchmaking.
keywords:

@ -1,12 +0,0 @@
# Install Open Match using Helm
This chart installs the Open Match application and defines deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
To deploy this chart run:
```bash
helm upgrade --install --wait --debug open-match install/helm/open-match \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
```

@ -1,314 +0,0 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 4,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Get Assignments",
"yaxis": 2
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(rate(statestore_createticket[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Create Ticket",
"refId": "A"
},
{
"expr": "sum(rate(statestore_indexticket[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Index Ticket",
"refId": "B"
},
{
"expr": "sum(rate(statestore_deindexticket[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Deindex Ticket",
"refId": "D"
},
{
"expr": "sum(rate(statestore_updateassignment[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Update Assignment",
"refId": "F"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Write Operations",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "wps",
"label": null,
"logBase": 2,
"max": null,
"min": "0",
"show": true
},
{
"decimals": null,
"format": "rps",
"label": null,
"logBase": 2,
"max": null,
"min": "0",
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"fill": 1,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(rate(statestore_getassignments[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Get Assignment",
"refId": "A"
},
{
"expr": "sum(rate(statestore_filterticket[$timewindow]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Filter Ticket",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Read Operations",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "rps",
"label": null,
"logBase": 2,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"schemaVersion": 18,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {
"text": "5m",
"value": "5m"
},
"hide": 0,
"includeAll": false,
"label": "Time Window",
"multi": false,
"name": "timewindow",
"options": [
{
"selected": true,
"text": "5m",
"value": "5m"
},
{
"selected": false,
"text": "10m",
"value": "10m"
},
{
"selected": false,
"text": "15m",
"value": "15m"
},
{
"selected": false,
"text": "30m",
"value": "30m"
},
{
"selected": false,
"text": "1h",
"value": "1h"
},
{
"selected": false,
"text": "4h",
"value": "4h"
}
],
"query": "5m,10m,15m,30m,1h,4h",
"skipUrlSync": false,
"type": "custom"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Storage",
"uid": "4mIVcfSWz",
"version": 3
}

@ -1,15 +1,21 @@
dependencies:
- name: prometheus
repository: https://kubernetes-charts.storage.googleapis.com/
version: 8.14.0
- name: redis
repository: https://kubernetes-charts.storage.googleapis.com/
version: 8.0.9
- name: grafana
repository: https://kubernetes-charts.storage.googleapis.com/
version: 3.5.7
- name: jaeger
repository: https://kubernetes-charts-incubator.storage.googleapis.com/
version: 0.12.0
digest: sha256:46c589cecf346f749eebf700b2abfd5995361758adcc592881d7fae4abd1ea5f
generated: "2019-07-03T11:14:34.486446966-07:00"
- name: open-match-demo
repository: file://./subcharts/open-match-demo
version: 0.0.0-dev
- name: open-match-telemetry
repository: file://./subcharts/open-match-telemetry
version: 0.0.0-dev
- name: open-match-customize
repository: file://./subcharts/open-match-customize
version: 0.0.0-dev
- name: open-match-test
repository: file://./subcharts/open-match-test
version: 0.0.0-dev
- name: open-match-scale
repository: file://./subcharts/open-match-scale
version: 0.0.0-dev
digest: sha256:58df48dae8d884f81dc06a3a2150082d68b271fc204abb19da12d1bf892647e1
generated: "2019-09-18T01:18:15.939673104-07:00"

@ -12,22 +12,28 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# TIP: Find versions via `gsutil ls gs://kubernetes-charts`
dependencies:
- name: prometheus
version: 8.14.0
repository: https://kubernetes-charts.storage.googleapis.com/
condition: prometheus.enabled
- name: redis
version: 8.0.9
repository: https://kubernetes-charts.storage.googleapis.com/
condition: redis.enabled
- name: grafana
version: 3.5.7
repository: https://kubernetes-charts.storage.googleapis.com/
condition: grafana.enabled
- name: jaeger
version: 0.12.0
repository: https://kubernetes-charts-incubator.storage.googleapis.com/
condition: jaeger.enabled
condition: open-match-core.enabled
- name: open-match-demo
version: 0.0.0-dev
condition: open-match-demo.enabled
repository: "file://./subcharts/open-match-demo"
- name: open-match-telemetry
version: 0.0.0-dev
condition: open-match-telemetry.enabled
repository: "file://./subcharts/open-match-telemetry"
- name: open-match-customize
version: 0.0.0-dev
condition: open-match-customize.enabled
repository: "file://./subcharts/open-match-customize"
- name: open-match-test
version: 0.0.0-dev
condition: open-match-test.enabled
repository: "file://./subcharts/open-match-test"
- name: open-match-scale
version: 0.0.0-dev
condition: open-match-scale.enabled
repository: "file://./subcharts/open-match-scale"

@ -0,0 +1,19 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: open-match-customize
version: 0.0.0-dev

@ -0,0 +1,40 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: ConfigMap
metadata:
name: customize-configmap
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: config
release: {{ .Release.Name }}
data:
matchmaker_config_override.yaml: |-
api:
mmlogic:
hostname: "{{ .Values.mmlogic.hostName }}"
grpcport: "{{ .Values.mmlogic.grpcPort }}"
functions:
hostname: "{{ .Values.function.hostName }}"
grpcport: "{{ .Values.function.grpcPort }}"
httpport: "{{ .Values.function.httpPort }}"
evaluator:
hostname: "{{ .Values.evaluator.hostName }}"
grpcport: "{{ .Values.evaluator.grpcPort }}"
httpport: "{{ .Values.evaluator.httpPort }}"

@ -0,0 +1,98 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
kind: Service
apiVersion: v1
metadata:
name: {{ .Values.evaluator.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: evaluator
release: {{ .Release.Name }}
spec:
selector:
app: {{ template "openmatch.name" . }}
component: evaluator
release: {{ .Release.Name }}
{{- $portType := coalesce .Values.global.kubernetes.service.portType .Values.evaluator.portType -}}
{{- if eq $portType "ClusterIP" }}
clusterIP: None
{{- end }}
type: {{ $portType }}
ports:
- name: grpc
protocol: TCP
port: {{ .Values.evaluator.grpcPort }}
- name: http
protocol: TCP
port: {{ .Values.evaluator.httpPort }}
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ .Values.evaluator.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Values.evaluator.hostName }}
{{- include "openmatch.HorizontalPodAutoscaler.spec.common" . | nindent 2 }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.evaluator.hostName }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "openmatch.name" . }}
component: evaluator
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.evaluator.replicas }}
selector:
matchLabels:
app: {{ template "openmatch.name" . }}
component: evaluator
template:
metadata:
namespace: {{ .Release.Namespace }}
annotations:
{{- include "prometheus.annotations" (dict "port" .Values.evaluator.httpPort "prometheus" .Values.global.telemetry.prometheus) | nindent 8 }}
{{- include "openmatch.chartmeta" . | nindent 8 }}
labels:
app: {{ template "openmatch.name" . }}
component: evaluator
release: {{ .Release.Name }}
spec:
volumes:
{{- include "openmatch.volumes.configs" . | nindent 8}}
{{- include "openmatch.volumes.tls" . | nindent 8}}
serviceAccountName: {{ .Values.global.kubernetes.serviceAccount }}
containers:
- name: {{ .Values.evaluator.hostName }}
volumeMounts:
{{- include "openmatch.volumemounts.configs" . | nindent 10 }}
{{- include "openmatch.volumemounts.tls" . | nindent 10 }}
image: "{{ .Values.global.image.registry }}/{{ .Values.evaluator.image}}:{{ .Values.global.image.tag }}"
ports:
- name: grpc
containerPort: {{ .Values.evaluator.grpcPort }}
- name: http
containerPort: {{ .Values.evaluator.httpPort }}
{{- include "openmatch.container.common" . | nindent 8 }}
{{- include "kubernetes.probe" (dict "port" .Values.evaluator.httpPort "isHTTPS" .Values.global.tls.enabled) | nindent 8 }}

@ -0,0 +1,99 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
kind: Service
apiVersion: v1
metadata:
name: {{ .Values.function.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: matchfunction
release: {{ .Release.Name }}
spec:
selector:
app: {{ template "openmatch.name" . }}
component: matchfunction
release: {{ .Release.Name }}
{{- $portType := coalesce .Values.global.kubernetes.service.portType .Values.function.portType -}}
{{- if eq $portType "ClusterIP" }}
clusterIP: None
{{- end }}
type: {{ $portType }}
ports:
- name: grpc
protocol: TCP
port: {{ .Values.function.grpcPort }}
- name: http
protocol: TCP
port: {{ .Values.function.httpPort }}
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ .Values.function.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Values.function.hostName }}
{{- include "openmatch.HorizontalPodAutoscaler.spec.common" . | nindent 2 }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.function.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: matchfunction
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.function.replicas }}
selector:
matchLabels:
app: {{ template "openmatch.name" . }}
component: matchfunction
template:
metadata:
namespace: {{ .Release.Namespace }}
annotations:
{{- include "prometheus.annotations" (dict "port" .Values.function.httpPort "prometheus" .Values.global.telemetry.prometheus) | nindent 8 }}
{{- include "openmatch.chartmeta" . | nindent 8 }}
labels:
app: {{ template "openmatch.name" . }}
component: matchfunction
release: {{ .Release.Name }}
spec:
volumes:
{{- include "openmatch.volumes.configs" . | nindent 8}}
{{- include "openmatch.volumes.tls" . | nindent 8}}
serviceAccountName: {{ .Values.global.kubernetes.serviceAccount }}
containers:
- name: {{ .Values.function.hostName }}
volumeMounts:
{{- include "openmatch.volumemounts.configs" . | nindent 10 }}
{{- include "openmatch.volumemounts.tls" . | nindent 10 }}
image: "{{ .Values.global.image.registry }}/{{ .Values.function.image}}:{{ .Values.global.image.tag }}"
ports:
- name: grpc
containerPort: {{ .Values.function.grpcPort }}
- name: http
containerPort: {{ .Values.function.httpPort }}
{{- include "openmatch.container.common" . | nindent 8 }}
{{- include "kubernetes.probe" (dict "port" .Values.function.httpPort "isHTTPS" .Values.global.tls.enabled) | nindent 8 }}

@ -0,0 +1,36 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Default values for open-match-test.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
function:
replicas: 3
portType: ClusterIP
image: openmatch-mmf-go-soloduel
evaluator:
replicas: 3
portType: ClusterIP
image: openmatch-evaluator-go-simple
configs:
# TODO: Remove this bit after deprecating the harness dependency on configmap
om-configmap-default:
volumeName: om-config-volume-default
mountPath: /app/config/default
customize-configmap:
volumeName: customize-config-volume
mountPath: /app/config/override

@ -0,0 +1,19 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: open-match-demo
version: 0.0.0-dev

@ -0,0 +1,39 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-configmap
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: config
release: {{ .Release.Name }}
data:
matchmaker_config.yaml: |-
api:
functions:
hostname: "{{ .Values.function.hostName }}"
grpcport: "{{ .Values.function.grpcPort }}"
demo:
hostname: "{{ .Values.demo.hostName }}"
httpport: "{{ .Values.demo.httpPort }}"
frontend:
hostname: "{{ .Values.frontend.hostName }}"
grpcport: "{{ .Values.frontend.grpcPort }}"
backend:
hostname: "{{ .Values.backend.hostName }}"
grpcport: "{{ .Values.backend.grpcPort }}"

@ -0,0 +1,75 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
kind: Service
apiVersion: v1
metadata:
name: {{ .Values.demo.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: demo
release: {{ .Release.Name }}
spec:
selector:
app: {{ template "openmatch.name" . }}
component: demo
type: {{ coalesce .Values.global.kubernetes.service.portType .Values.demo.portType }}
ports:
- name: http
protocol: TCP
port: {{ .Values.demo.httpPort }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.demo.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: demo
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.demo.replicas }}
selector:
matchLabels:
app: {{ template "openmatch.name" . }}
component: demo
template:
metadata:
namespace: {{ .Release.Namespace }}
annotations:
{{- include "openmatch.chartmeta" . | nindent 8 }}
labels:
app: {{ template "openmatch.name" . }}
component: demo
release: {{ .Release.Name }}
spec:
volumes:
{{- include "openmatch.volumes.configs" . | nindent 8}}
{{- include "openmatch.volumes.tls" . | nindent 8}}
serviceAccountName: {{ .Values.global.kubernetes.serviceAccount }}
containers:
- name: {{ .Values.demo.hostName }}
volumeMounts:
{{- include "openmatch.volumemounts.configs" . | nindent 10 }}
{{- include "openmatch.volumemounts.tls" . | nindent 10 }}
image: "{{ .Values.global.image.registry }}/{{ .Values.demo.image}}:{{ .Values.global.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.demo.httpPort }}
{{- include "kubernetes.probe" (dict "port" .Values.demo.httpPort) | nindent 8 }}

@ -0,0 +1,38 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Default values for open-match-demo.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
demo:
hostName: om-demo
httpPort: 51507
portType: ClusterIP
replicas: 1
image: openmatch-demo-first-match
image:
registry: gcr.io/open-match-public-images
tag: 0.0.0-dev
pullPolicy: Always
# TODO: Split tls configs into a separate config file. For now Open Match assumes core components share the same secure mode
# with the mmfs and evaluator, so we have to copy these secure settings and define a new configmap for it whenever we what
# to create a new evaluator and mmf. We should create a global configmap for the security settings for all subcharts
# under the /install/helm/open-match directory to avoid copy&paste files around.
configs:
demo-configmap:
mountPath: /app/config/om
volumeName: demo-config-volume

@ -0,0 +1,19 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: open-match-scale
version: 0.0.0-dev

@ -12,58 +12,62 @@
# See the License for the specific language governing permissions and
# limitations under the License.
{{- if .Values.openmatch.demo.install }}
kind: Service
apiVersion: v1
metadata:
name: om-demo
name: {{ .Values.scaleBackend.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
{{- include "openmatch.chartmeta" (set . "indent" 4) }}
component: scaleBackend
release: {{ .Release.Name }}
spec:
selector:
app: {{ template "openmatch.name" . }}
component: demo
type: {{ .Values.openmatch.demo.porttype }}
component: scaleBackend
ports:
- name: http
protocol: TCP
port: {{ .Values.openmatch.demo.http.port }}
port: {{ .Values.scaleBackend.httpPort }}
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: om-demo
name: {{ .Values.scaleBackend.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: demo
{{- include "openmatch.chartmeta" (set . "indent" 4) }}
component: scaleBackend
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.openmatch.demo.replicas }}
replicas: {{ .Values.scaleBackend.replicas }}
selector:
matchLabels:
app: {{ template "openmatch.name" . }}
component: demo
{{- include "openmatch.chartmeta" (set . "indent" 6) }}
component: scaleBackend
template:
metadata:
namespace: {{ .Release.Namespace }}
annotations:
{{- include "prometheus.annotations" (dict "port" .Values.openmatch.demo.http.port "prometheus" .Values.openmatch.telemetry.prometheus) | nindent 8 }}
{{- include "openmatch.chartmeta" . | nindent 8 }}
labels:
app: {{ template "openmatch.name" . }}
component: demo
{{- include "openmatch.chartmeta" (set . "indent" 8) }}
component: scaleBackend
release: {{ .Release.Name }}
spec:
{{- include "openmatch.spec.common" . | nindent 6 }}
volumes:
{{- include "openmatch.volumes.configs" . | nindent 8}}
{{- include "openmatch.volumes.tls" . | nindent 8}}
serviceAccountName: {{ .Values.global.kubernetes.serviceAccount }}
containers:
- name: om-demo
{{- include "openmatch.container.common" . | nindent 8 }}
image: "{{ .Values.openmatch.image.registry }}/{{ .Values.openmatch.image.demo.name}}:{{ .Values.openmatch.image.tag }}"
- name: {{ .Values.scaleBackend.hostName }}
volumeMounts:
{{- include "openmatch.volumemounts.configs" . | nindent 10 }}
{{- include "openmatch.volumemounts.tls" . | nindent 10 }}
image: "{{ .Values.global.image.registry }}/{{ .Values.scaleBackend.image}}:{{ .Values.global.image.tag }}"
ports:
- name: http
containerPort: {{ .Values.openmatch.demo.http.port }}
{{- include "kubernetes.probe" (dict "port" .Values.openmatch.demo.http.port) | nindent 8 }}
{{- end }}
containerPort: {{ .Values.scaleBackend.httpPort }}
{{- include "openmatch.container.common" . | nindent 8 }}

@ -0,0 +1,54 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: ConfigMap
metadata:
name: scale-configmap
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: config
release: {{ .Release.Name }}
data:
matchmaker_config.yaml: |-
api:
frontend:
hostname: "{{ .Values.frontend.hostName }}"
grpcport: "{{ .Values.frontend.grpcPort }}"
backend:
hostname: "{{ .Values.backend.hostName }}"
grpcport: "{{ .Values.backend.grpcPort }}"
testConfig:
profile: "{{ .Values.testConfig.profile }}"
concurrentCreates: "{{ .Values.testConfig.concurrentCreates }}"
regions:
{{- range .Values.testConfig.regions }}
- {{ . }}
{{- end }}
characters:
{{- range .Values.testConfig.characters }}
- {{ . }}
{{- end }}
minRating: "{{ .Values.testConfig.minRating }}"
maxRating: "{{ .Values.testConfig.maxRating }}"
ticketsPerMatch: "{{ .Values.testConfig.ticketsPerMatch }}"
multifilter:
rangeSize: "{{ .Values.testConfig.multifilter.rangeSize }}"
rangeOverlap: "{{ .Values.testConfig.multifilter.rangeOverlap }}"
multipool:
rangeSize: "{{ .Values.testConfig.multipool.rangeSize }}"
rangeOverlap: "{{ .Values.testConfig.multipool.rangeOverlap }}"
characterCount: "{{ .Values.testConfig.multipool.characterCount }}"

@ -0,0 +1,73 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
kind: Service
apiVersion: v1
metadata:
name: {{ .Values.scaleFrontend.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: scaleFrontend
release: {{ .Release.Name }}
spec:
selector:
app: {{ template "openmatch.name" . }}
component: scaleFrontend
ports:
- name: http
protocol: TCP
port: {{ .Values.scaleFrontend.httpPort }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.scaleFrontend.hostName }}
namespace: {{ .Release.Namespace }}
annotations: {{- include "openmatch.chartmeta" . | nindent 4 }}
labels:
app: {{ template "openmatch.name" . }}
component: scaleFrontend
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.scaleFrontend.replicas }}
selector:
matchLabels:
app: {{ template "openmatch.name" . }}
component: scaleFrontend
template:
metadata:
namespace: {{ .Release.Namespace }}
annotations:
{{- include "openmatch.chartmeta" . | nindent 8 }}
labels:
app: {{ template "openmatch.name" . }}
component: scaleFrontend
release: {{ .Release.Name }}
spec:
volumes:
{{- include "openmatch.volumes.configs" . | nindent 8}}
{{- include "openmatch.volumes.tls" . | nindent 8}}
serviceAccountName: {{ .Values.global.kubernetes.serviceAccount }}
containers:
- name: {{ .Values.scaleFrontend.hostName }}
volumeMounts:
{{- include "openmatch.volumemounts.configs" . | nindent 10 }}
{{- include "openmatch.volumemounts.tls" . | nindent 10 }}
image: "{{ .Values.global.image.registry }}/{{ .Values.scaleFrontend.image}}:{{ .Values.global.image.tag }}"
ports:
- name: http
containerPort: {{ .Values.scaleFrontend.httpPort }}
{{- include "openmatch.container.common" . | nindent 8 }}

@ -0,0 +1,52 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
scaleFrontend:
hostName: om-scale-frontend
httpPort: 51509
replicas: 1
image: openmatch-scale-frontend
scaleBackend:
hostName: om-scale-backend
httpPort: 51510
replicas: 1
image: openmatch-scale-backend
configs:
scale-configmap:
mountPath: /app/config/om
volumeName: scale-config-volume
testConfig:
profile: greedy
concurrentCreates: 500
regions:
- region.europe-west1
- region.europe-west2
- region.europe-west3
- region.europe-west4
characters:
- cleric
- knight
minRating: 0
maxRating: 100
ticketsPerMatch: 8
multifilter:
rangeSize: 10
rangeOverlap: 5
multipool:
rangeSize: 10
rangeOverlap: 5
characterCount: 4

@ -0,0 +1,19 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: open-match-telemetry
version: 0.0.0-dev

Some files were not shown because too many files have changed in this diff Show More