Skip to content

Commit

Permalink
Adds Satori client package (#141)
Browse files Browse the repository at this point in the history
* Adds Satori client package

* Rename serverKey to apiKey and add support for multiple events using the events function

* Fix typo in event test payload
  • Loading branch information
tomglenn authored Jan 12, 2023
1 parent 6e45c96 commit 8891f9e
Show file tree
Hide file tree
Showing 30 changed files with 7,333 additions and 508 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [keep a changelog](http://keepachangelog.com/) and this p

### Unreleased

### Added
- Added [Satori](https://heroiclabs.com/docs/satori) client package (`satori-js`)

### [2.4.1]

### Fixed
Expand Down
685 changes: 179 additions & 506 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
"packages/nakama-js-protobuf",
"packages/nakama-js-react-native-example",
"packages/nakama-js-test",
"packages/nakama-js-webpack-example"
"packages/nakama-js-webpack-example",
"packages/satori-js",
"packages/satori-js-test"
]
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/nakama-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@heroiclabs/nakama-js",
"version": "2.4.1",
"version": "2.5.0",
"scripts": {
"build": "node build.js",
"docs": "typedoc index.ts --gaID UA-89839802-1 --out ../../docs"
Expand Down
72 changes: 72 additions & 0 deletions packages/satori-js-test/client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright 2018 The Nakama Authors
*
* 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.
*/

import {Page} from "puppeteer"
import * as satorijs from "@heroiclabs/satori-js";
import {createPage} from "./utils"
import {describe, expect, it} from '@jest/globals'

describe('Client Tests', () => {

it('should create object with defaults', async () => {
const page : Page = await createPage();

const client = await page.evaluate(() => {
return new satorijs.Client();
});

expect(client).not.toBeNull();
expect(client.serverkey).toBe("defaultkey");
expect(client.host).toBe("127.0.0.1");
expect(client.port).toBe("7350");
expect(client.useSSL).toBe(false);
expect(client.timeout).toBe(7000);
});

it('should create object with configuration', async () => {
const page : Page = await createPage();

const SERVER_KEY = "somesecret!";
const HOST = "127.0.0.2";
const PORT = "8080";
const SSL = true;
const TIMEOUT = 8000;

const client = await page.evaluate((SERVER_KEY, HOST, PORT, SSL, TIMEOUT) => {
return new satorijs.Client(SERVER_KEY, HOST, PORT, SSL, TIMEOUT);
}, SERVER_KEY, HOST, PORT, SSL, TIMEOUT);

expect(client).not.toBeNull();
expect(client.serverkey).toBe(SERVER_KEY);
expect(client.host).toBe(HOST);
expect(client.port).toBe(PORT);
expect(client.useSSL).toBe(SSL);
expect(client.timeout).toBe(TIMEOUT);
});

it('should obey timeout configuration option', async () => {
const page : Page = await createPage();

const err = await page.evaluate(() => {
const client = new satorijs.Client("defaultkey", "127.0.0.1", "7350", false, 0);
return client.authenticate("timeoutuseridentifier")
.catch(err => err);
});

expect(err).not.toBeNull();
expect(err).toBe("Request timed out.");
});
});
42 changes: 42 additions & 0 deletions packages/satori-js-test/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Satori JS Browser Test</title>
</head>
<body>
<script src="../satori-js/dist/satori-js.iife.js"></script>

<script>
const client = new satorijs.Client("a63e9083-375c-4169-ad0b-dccb86bdb98b");
const customid = "uniqueuser";
var _session;

client.authenticate(customid)
.then(session => {
_session = session;
console.log("session", session);
client.sessionRefresh(session).then((session) => console.log("session refreshed, new token: ", session.token));
client.event(session, { name: "testEvent", value: "A value", metadata: { hello: "world" }}).then(() => console.log("sent event"));
client.events(session, [
{ name: "sampleEventOne", value: "One", metadata: { meta: "data" }},
{ name: "sampleEventTwo", value: "Two", metadata: { data: "meta" }}
]).then(() => console.log("sent event"));
client.updateProperties(session, { email: "[email protected]" }, { customProperty1: "A value here" });
client.listProperties(session).then((result) => console.log("properties:", result));
client.getExperiments(session, []).then((result) => console.log("experiments: ", result));
client.getFlags(session, []).then((result) => console.log("flags: ", result));
client.getLiveEvents(session, []).then((result) => console.log("live events:", result));
// client.identify(session, "anotheruser", { "email": "foo@bar.com" }, { "customProperty1": "aValue" })
// .then(newSession => console.log("got new session by calling identify", newSession))
// .catch(error => {
// console.log("got an error:", error);
// });
//client.logout(session).then(() => console.log("logged out"));
}).catch(error => {
console.log(error);
});
</script>
</body>
</html>
13 changes: 13 additions & 0 deletions packages/satori-js-test/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const merge = require('merge')
const ts_preset = require('ts-jest/jest-preset')
const puppeteer_preset = require('jest-puppeteer/jest-preset')

//use multiple jest presets by merging and exporting them as a single object
module.exports = merge.recursive(ts_preset, puppeteer_preset, {
globals: {
'ts-jest': {
tsConfig: 'tsconfig.test.json'
}
}
}
)
24 changes: 24 additions & 0 deletions packages/satori-js-test/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@heroiclabs/satori-js-test",
"version": "1.0.0",
"description": "A subproject that houses tests for Satori JS",
"private": true,
"license": "Apache-2.0",
"dependencies": {
"@heroiclabs/satori-js": "1.0.0"
},
"devDependencies": {
"@types/expect-puppeteer": "^4.4.5",
"@types/jest": "^26.0.20",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/node": "12.12.6",
"@types/puppeteer": "^5.4.2",
"jest": "26.6.0",
"jest-puppeteer": "^4.4.0",
"puppeteer": "5.5.0",
"ts-jest": "26.4.4"
},
"scripts": {
"test": "npx typescript --project tsconfig.test.json && jest --runInBand"
}
}
24 changes: 24 additions & 0 deletions packages/satori-js-test/tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"lib": [
"dom",
"es2015",
"es2016",
"es2017"
],
"target": "es2018",
"module": "es2015",
"removeComments": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"noEmitHelpers": false,
"importHelpers": false,
"baseUrl": "./",
"noEmit": true,
"allowSyntheticDefaultImports": true
},
"include": [
"./*",
],
"exclude": []
}
103 changes: 103 additions & 0 deletions packages/satori-js-test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Copyright 2020 The Nakama Authors
*
* 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.
*/

import { Page, Browser} from "puppeteer";
const fs = require("fs");
const crypto = require("crypto");
const base64url = require("base64url");

// automatically assigned by puppeteer + Jest
declare var browser : Browser;

// automatically assigned by puppeteer + Jest
declare var browser : Browser;

// util to generate a random id.
export function generateid(): string {
const arr: string[] = [];

for (let i: number = 0; i < 30; i++) {
arr.push(Math.random().toString(36)[3]);
}

return arr.join("");
};

export async function createPage(): Promise<Page> {

const page = await browser.newPage();

page.on('console', msg => console.log('LOG:', msg.text()));
page.on('error', handlePageError);
page.on('pageerror', handlePageError);

const nakamaJsLib = fs.readFileSync(__dirname + '/../nakama-js/dist/nakama-js.iife.js', 'utf8');
const nakamaJsProtobufLib = fs.readFileSync(__dirname + '/../nakama-js-protobuf/dist/nakama-js-protobuf.iife.js', 'utf8');

await page.evaluateOnNewDocument(nakamaJsLib);
await page.evaluateOnNewDocument(nakamaJsProtobufLib);
await page.evaluateOnNewDocument(() => {
globalThis.timeoutPromise = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
})

await page.goto('about:blank');

return page;
}

function handlePageError(err) {

let msg: string;

if (err instanceof Object) {
msg = JSON.stringify(err);
}
else {
msg = err;
}

console.error('ERR:', msg);
}

export const enum AdapterType {
Text = 0,
Protobuf = 1
}

export const adapters = [AdapterType.Text, AdapterType.Protobuf];

export function createFacebookInstantGameAuthToken(id : string) : string {
const testSecret = "fb-instant-test-secret";

const mockFbInstantPayload = JSON.stringify({
algorithm: "HMAC-SHA256",
issued_at: 1594867628,
player_id: id,
request_payload: ""
});

const encodedPayload = base64url(mockFbInstantPayload);

const signature = crypto.createHmac('sha256', testSecret).update(encodedPayload).digest();
const encodedSignature = base64url(signature);

const token = encodedSignature + "." + encodedPayload;
return token;
}

export const matchmakerTimeout = 20000;
Loading

0 comments on commit 8891f9e

Please sign in to comment.