Chat Webhooks
Use webhooks with Photon Cloud to have more control over your chat applications.
You can persist channel history, filter messages, cancel channel creation and even prohibit certain players from subscribing to chat channels.
Photon Chat webhooks are event-driven HTTP POST requests sent by Photon Cloud to specific URLs.
Each Photon Chat webhook is defined by its own triggers, data and destination path.
Setup
Basic Settings
- BaseUrl (required)
The URL for the service hosting your hooks.
It must not end with a forward slash.
Callbacks are received at the relative path URIs of the configured hooks.
Read this if the value you want to configure will contain a query string. - CustomHttpHeaders
JSON string of key/value pairs (string:string) that should be set as HTTP headers in any request made to the configured web service.
Read more here.
Paths
Configure each path to receive events at the URIs each identifies on your host.
Any path that is left empty will not be hit, you will not receive any callbacks on the affected webhook.
Read this if the value you want to configure will contain a query string.
- PathChannelCreate
Called when a new channel is created or when its state needs to be loaded from external service. - PathChannelDestroy
Called when a channel is removed from Photon servers memory.
If IsPersistent is set totruethe channel state is sent. - PathChannelSubscribe
Called when a player subscribes to an already created channel. - PathChannelUnsubscribe
Called when a player unsubscribes from a channel. - PathPublishMessage
Called when the client publishes a message in a channel or sends a private message.
The client should explicitly choose to HTTP forward the message as a webhook.
Options
Fine-tune the behaviour of your chat webhooks configuration with these options.
An option is considered not configured when not set up or if its value is left empty.
- FailIfUnavailable
If set totrue, channel creation, subscription and publish message operations will fail when the corresponding hook's configured endpoint is not available.
An endpoint is considered unavailable when an error occurs during the process of its HTTP request or when the HTTP response is not successful.
Default isfalse. - IsPersistent
If set totrue, Photon Cloud sends the channel state before destroying it.
This option is only valid when both PathChannelCreate and PathChannelDestory are properly configured and MaxChannelHistory is greater than 0.
For more information please read more about ChannelCreate and ChannelDestroy webhooks.
Default isfalse. - MaxChannelHistory
Maximum number of messages to be persisted per channel.
It should be between 1 and 100.
Default is 100. - HasErrorInfo
If set totrue, Chat clients will be notified with an error message when a hook endpoint (PathUnsubscribe or PathChannelDestory excluded) is unavailable but FailIfUnavailable is set tofalse.
Default isfalse. - SkipPostCreationFailure
If set totrue, PathUnsubscribe and PathChannelDestory webhooks will not be sent after a channel creation failure.
Default isfalse.
쿼리 문자열 처리 (Query String Handling)
쿼리 문자열 매개변수는 BaseUrl 또는 Path에 포함될 수 있습니다.
이를 사용할 경우 다음 사항을 알아두어야 합니다:
- 쿼리 문자열 매개변수는 UTF8 인코딩을 사용해 파싱 됩니다.
- 동일한 쿼리 문자열 매개변수가 동일 설정 내에서 여러 번 발견되면, 하나의 매개변수로 병합되며 각 값은 쉼표(,)로 구분됩니다.
쉼표는%2c로 이스케이프 됩니다. - 동일한 매개변수 키가 BaseUrl과 Path에 동시에 존재할 경우, Path에 있는 값이 사용됩니다.
- 값이 없는 매개변수도 허용됩니다.
- 키가 없는 매개변수도 허용됩니다.
이 경우 키는 빈 문자열로 간주됩니다.
BaseUrl과 Path 모두에 키가 없는 매개변수가 있을 경우, Path에 있는 값만 사용됩니다. - 쿼리 문자열 매개변수는 URL 인코딩됩니다.
- 쿼리 문자열 매개변수에서 URL 태그를 사용할 수 있습니다.
예시:
설정:
- BaseUrl:
https://myawesomegame.com/chat/webhooks?clientver={AppVersion}&key=&keyA=valueA&keyA=valueB&keyB=valueB&=value - PathChannelCreate:
create?key=X&keyA=valueC - PathChannelDestroy:
destroy?keyB=valueC&keyC=valueC&=valueD&=valueE
- BaseUrl:
결과 URL:
- PathChannelCreate:
https://myawesomegame.com/chat/webhooks/create?clientver=1.0&key=X&keyA=valueC&keyB=valueB&=value - PathChannelDestroy:
https://myawesomegame.com/chat/webhooks/destroy?clientver=1.1&key=&keyA=valueA%2cvalueB&keyB=valueC&keyC=valueC&=valueD%2cvalueE
- PathChannelCreate:
HTTP 헤더 관련 고려 사항
사용자 지정 HTTP 헤더를 사용할 때 다음 사항들을 고려해야 합니다:
CustomHttpHeaders설정 키의 값은 문자열화된 JSON 객체여야 하며, 해당 객체의 속성 값은 모두 문자열이어야 합니다.
이 JSON 객체의 속성 이름은 HTTP 요청 헤더 필드 이름으로 사용되며, 속성 값은 각각의 헤더 값으로 사용됩니다.
예시:- CustomHttpHeaders 값:
{'X-Secret': 'YWxhZGRpbjpvcGVuc2VzYW1l', 'X-Origin': 'Photon'} - Webhooks HTTP 요청 헤더:
X-Secret: YWxhZGRpbjpvcGVuc2VzYW1l X-Origin: Photon
- CustomHttpHeaders 값:
사용자 지정 HTTP 헤더 필드 이름은 대소문자를 구분합니다.
아래에 나열된 HTTP 헤더는 제한된 필드로 간주되며,
"CustomHttpHeaders"설정값에서 설정하더라도 무시됩니다:ConnectionContent-LengthHostRangeProxy-Connection
URL 태그
대시보드에서 Webhooks 또는 WebRpc 의 기준 URL을 설정 할 때 하나 이상의 "동적 변수"를 설정 할 수 있습니다.
이러한 변수들은 요청을 전송하기 전에 백엔드에서 상응하는 값들로 교체 되게 됩니다.
어플리케이션에서 사용자들을 서로 다르게 분리하여 처리를 원할 때 URL 태그는 매우 간편합니다.
Photon 은 다음의 URL 태그들을 지원합니다:
{AppVersion}은 클라이언트에서 설정된 어플리케이션 버전을 전달 합니다.{AppId}는 어플리케이션의 ID 를 전달 합니다.{Region}은 클라이언트가 접속된 클라우드 지역에 대한 토큰을 전달 합니다. 예, "eu".{Cloud}는 클라이언트가 연결된 클라우드의 이름을 전달 합니다. 예, "public" 또는 "enigmaticenterprise".
URL 태그 유즈케이스의 예제
https://{Region}.mydomain.com/{AppId}?version={AppVersion}&cloud={Cloud}https://mydomain.com/{Cloud}/{Region}/{AppId}/{AppVersion}
Common Request Arguments
AppId:
AppId of your application as set from the game client and found in the dashboard.
AppVersion:
Version of your application as set from the game client.
Region:
Has the region to which the game client is connected to and to which the room in question belongs to.
ChannelType:
The channel type: "Public" for public channels and "Private" for private channels.
UserId:
UserID of the player triggering the hook. (Except ChannelDestory)
HistoryCount:
The current count of messages in the channel history. (Except ChannelDestory)
ChannelName:
The name of the channel in which the hook is triggered. (Only public channels)
UsersPair:
Array of two strings containing the UserIDs of the two ends of the private channel. (Only private channels)
Request Arguments List
This table gives you what arguments are available for each webhook for public channels:
| Argument |
ChannelCreate / ChannelSubscribe |
ChannelDestroy | PublishMessage | ChannelUnsubscribe |
|---|---|---|---|---|
| AppId | ||||
| AppVersion | ||||
| Region | ||||
| ChannelType ("Public") | ||||
| ChannelName | ||||
| HistoryLen | ||||
| HistoryCount | ||||
| UserId | ||||
| ChannelState | (conditions apply) | |||
| Message |
For private channels, there is a single webhook PublishMessage with the following arguments:
AppIdAppVersionRegionChannelType(set to "Private")UsersPairHistoryCountUserId
Paths in Details
ChannelCreate
This webhook is sent when a channel is about to be created on Photon servers.
If you have a previously saved the ChannelState, you need to return it in the webhooks response to load its history.
See "Return Values" for an example.
Specific Arguments
HistoryLen:
It forwards the parameter with same name set by client in subscribe operation.
It contains the number of messages from the history requested by the client.
Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Public",
"ChannelName":"PersistentChannel",
"HistoryLen":10,
"UserId":"testClient1"
}
ChannelDestroy
This webhook is sent when a channel is about to be destroyed on Photon servers.
This happens when an empty channel times out.
A channel is considered empty when it does not contain any subscriber, because they left.
Default empty channel timeout value is 5 seconds.
If IsPersistent is set to true and PathChannelDestory is configured properly,
ChannelState will be sent in the webhook body.
In the ChannelState, the History object is just for debugging purposes. You may discard it.
Photon servers use the BinaryHistory to persist data types.
You should save it as is if you want to load channel history later.
Specific Arguments
ChannelState:
A serializable channel state.
Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Public",
"ChannelName":"PersistentChannel",
"HistoryCount":2,
"ChannelState":{
"ChannelHistoryCapacity":100,
"BinaryHistory": "RGl6AAEAAAAAAAN6AANp..",
"History":{
"MessageIdBase":2,
"Entries":[
{
"Message":"msg1",
"Sender":"testClient1",
"MsgId":1
},
{
"Message":"msg2",
"Sender":"testClient2",
"MsgId":2
}
]
}
}
}
ChannelSubscribe
This webhook is triggered by client subscription to an already created channel.
The client is either:
- not the first subscriber. This should be the most frequent case.
- the first subscriber when the channel is empty and did not time out. This is unlikely because it is a small window.
Specific Arguments
HistoryLen:
It forwards the parameter with same name set by client in subscribe operation.
It contains the number of messages from the history requested by the client.
Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Public",
"ChannelName":"PersistentChannel",
"HistoryLen":-1,
"HistoryCount": 1,
"UserId":"testClient2"
}
ChannelUnsubscribe
This webhook is triggered when a client disconnects from a channel, which can be caused by any of the following reasons:
- explicit call to unsubscribe operation.
- explicit disconnection.
- timeout disconnection.
- channel creation failure and SkipPostCreationFailure is set to
false. - subscription failure.
Specific Arguments
ChannelUnsubscribe has no extra arguments.
Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Public",
"ChannelName":"PersistentChannel",
"HistoryCount":2,
"UserId":"testClient2"
}
PublishMessage
This webhook is triggered when a client publishes a message into the channel or sends a private message to a user.
The client should explicitly choose to HTTP forward the message as a webhook using the appropriate WebFlag.
If you want to replace the message to be published you can return the new one in Data parameter.
The value of the returned webhook response's Data property will be published inside the channel instead of the original message content sent by the client.
See "Return Values" for an example.
You can choose any type of data as long as it is supported by Photon serialization.
One use case for this could be data polling from the web server.
Also making use of the Data return parameter may result in a behavior that could be compared to Photon Realtime's WebRPC.
Specific Arguments
Message: Message to be published to all subscribers of the channel. Forwarded as sent from client.
Public Channel: Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Public",
"ChannelName":"PersistentChannel",
"HistoryCount":1,
"UserId":"testClient2",
"Message":"msg2"
}
Private Channel: Sample Call
text
{
"AppId":"00000000-0000-0000-0000-000000000000",
"AppVersion":"1.0",
"Region":"EU",
"ChannelType":"Private",
"UsersPair":["testClient1", "testClient2"],
"HistoryCount":1,
"UserId":"testClient2",
"Message":"msg2"
}
Return Values
All webhooks expect a JSON object containing a ResultCode which can be:
- 0 for success.
Sample Success Response
text
{
"ResultCode":0,
"DebugMessage":"OK"
}
- any other integer for failure.
Sample Failure Response
text
{
"ResultCode":1,
"DebugMessage":"A nice self-explanatory error message"
}
"PublishMessage" webhook supports an extra property from the web server which is Data.
Sample "Full" PublishMessage Response
text
{
"ResultCode":0,
"DebugMessage":"Message Will Be Overridden By Server",
"Data": "Anything you want and supported by Photon Serialization"
}
"ChannelCreate" webhook supports an extra property from web server which is the ChannelState.
Sample "Full" ChannelCreate Response
text
{
"ResultCode":0,
"DebugMessage":"ChannelState Loaded Successfully",
"ChannelState":{
"ChannelHistoryCapacity":100,
"BinaryHistory": "RGl6AAEAAAAAAAN6AANp..",
"History":{
"MessageIdBase":2,
"Entries":[
{
"Message":"msg1",
"Sender":"testClient1",
"MsgId":1
},
{
"Message":"msg2",
"Sender":"testClient2",
"MsgId":2
}
]
}
}
}
Since "History" is not required for loading the state as it's useful for debugging, you may discard it when saving the state or when loading it.
Sample "Stripped" ChannelCreate Response
text
{
"ResultCode":0,
"DebugMessage":"ChannelState Loaded Successfully",
"ChannelState":{
"ChannelHistoryCapacity":100,
"BinaryHistory": "RGl6AAEAAAAAAAN6AANp.."
}
}
It is considered a best practice to:
- have a list of reserved
ResultCodevalues per custom user error type. - return a
DebugMessagestring which can be useful for debugging.
Response Arguments List
This table gives you what response arguments are supported for each webhook for public channels:
| Argument | ChannelCreate | PublishMessage | others |
|---|---|---|---|
| ResultCode | |||
| DebugMessage | (optional) | (optional) | (optional) |
| Data | (optional) | ||
| ChannelState | (optional) |
Cancelable Operations
The table below shows which chat operations could be canceled or aborted using webhooks.
To do so you need to return a ResultCode other than 0 and optionally a DebugMessage that you can find in the OperationResponse's DebugMessage.
| Webhook | Can Be Canceled |
|---|---|
| ChannelCreate | |
| ChannelDestory | |
| ChannelSubscribe | |
| ChannelUnsubscribe | |
| PublishMessage |
데이터 타입 변환
이 섹션에서는 Photon 서버와 웹 서비스간의 데이터 교환의 타입에 대해서만 설명합니다.
클라이언트와 Photon 서버간의 데이터 타입에 대해서는 Photon 의 직렬화 페이지를 참고 하시기 바랍니다.
Photon 서버 -> 웹 서비스
| C# / .NET (Photon 지원 타입) | JavaScript / JSON |
|---|---|
byte
|
number |
short
|
|
int
|
|
long
|
|
double
|
|
bool
|
bool |
string
|
string |
byte[] (byte 배열 length < short.MaxValue)
|
string (Base64 encoded) |
T[] (array of supported type T, length < short.MaxValue)
|
array |
Hashtable (of supported types, count < short.MaxValue, preferably Photon implementation)
|
object |
Dictionary (keys and values of supported types, count < short.MaxValue)
|
object |
null
|
null
|
샘플 요청 데이터 (타입들이 연결되어 있습니다)
Photon 서버 전송:
JavaScript
{
"(Dictionary<String,Object>)Dictionary":{
"(Int32)dk_int":"1",
"(String)dk_str":"dv2",
"(Boolean)dk_bool":"True"
},
"(Hashtable)Hashtable":{
"(Byte)hk_byte":"255",
"(Object[])hk_array":[
"(Object)0",
"(Object)xy",
"(Object)False"
],
"hk_null":"null"
},
"null":"null",
"(String[])string[]":[
"(String)PUN",
"(String)TB",
"(String)RT",
"(String)Bolt",
"(String)Chat"
],
"(Byte[])byte[]":[
"(Byte)255",
"(Byte)0"
],
"(Int16[])short[]":[
"(Int16)-32768",
"(Int16)32767"
],
"(Int32[])int[]":[
"(Int32)-2147483648",
"(Int32)2147483647"
],
"(Int64[])long[]":[
"(Int64)-9223372036854775808",
"(Int64)9223372036854775807"
],
"(Single[])float[]":[
"(Single)-3.402823E+38",
"(Single)3.402823E+38"
],
"(Double[])double[]":[
"(Double)-1.79769313486232E+308",
"(Double)1.79769313486232E+308"
],
"(Boolean[])bool[]":[
"(Boolean)True",
"(Boolean)False"
]
}
Web 서비스 수신:
JavaScript
{
"(object)Dictionary":{
"dk_int":"(number)1",
"dk_str":"(string)dv2",
"dk_bool":"(boolean)true"
},
"(object)Hashtable":{
"hk_byte":"(number)255",
"hk_null":null,
"hk_array":[
"(number)0",
"(string)xy",
"(boolean)false"
]
},
"null":null,
"(array)string[]":[
"(string)PUN",
"(string)TB",
"(string)RT",
"(string)Bolt",
"(string)Chat"
],
"byte[]":"(string)/wA=",
"(array)short[]":[
"(number)-32768",
"(number)32767"
],
"(array)int[]":[
"(number)-2147483648",
"(number)2147483647"
],
"(array)long[]":[
"(number)-9223372036854776000",
"(number)9223372036854776000"
],
"(array)float[]":[
"(number)-3.40282347e+38",
"(number)3.40282347e+38"
],
"(array)double[]":[
"(number)-1.7976931348623157e+308",
"(number)1.7976931348623157e+308"
],
"(array)bool[]":[
"(boolean)true",
"(boolean)false"
]
}
웹 서비스 -> Photon 서버
C#/.Net 에서 JavaScript/JSON 타입과 각각 대응하는 테이블입니다.
Here is a table that matches each JavaScript/JSON type to its equivalent one in C#/.Net :
| JavaScript / JSON | C# / .Net |
|---|---|
| object |
Dictionary
|
| array |
object[] (array of objects)
|
| number (integral) |
long
|
| number (floating) |
double
|
| string |
string
|
| boolean |
bool
|
null (not a type)
|
null
|
undefined (when sent)
|
null
|
응답 데이터 샘플 (타입들이 연결되어 있습니다)
Web Service 전송:
JavaScript
{
"(object)number": {
"MAX_VALUE": "(number)1.7976931348623157e+308",
"MIN_VALUE": "(number)5e-324"
},
"(object)object": {
"string": "(string)xyz",
"null": null,
"bool": "(boolean)false",
"undefined": "(undefined)undefined",
"number": "(number)-3.14"
},
"(array)array": [
"(string)xyz",
"(number)0",
"(boolean)true",
null,
"(undefined)undefined"
]
}
Photon Server 수신:
JavaScript
{
"(Dictionary<String,Object>)number":{
"(Double)MAX_VALUE":"1.79769313486232E+308",
"(Double)MIN_VALUE":"4.94065645841247E-324"
},
"(Dictionary<String,Object>)object":{
"(String)string":"xyz",
"null":"null",
"(Boolean)bool":"False",
"(Double)number":"-3.14"
},
"(Object[])array":[
"(Object)xyz",
"(Object)0",
"(Object)True",
"null",
"null"
]
}
Securing Webhooks
Other than using HTTPS and newer TLS version, you can enforce webhooks security using custom HTTP request headers or query string parameters.
The idea is that you set up one or more "secrets" ("token", "key", etc.) from Photon dashboard that can help you make sure that the incoming HTTP requests are originating from Photon servers.