Skip to content

Commit

Permalink
[MOD] The server side authenticate function can return a promise and …
Browse files Browse the repository at this point in the history
…is waited

[FIX] React example
[MOD] Readme
  • Loading branch information
ivan-topp committed Oct 27, 2022
1 parent f18f9cc commit 30fc527
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 16 deletions.
5 changes: 3 additions & 2 deletions README.md
Expand Up @@ -121,8 +121,9 @@ import { YSocketIO } from 'y-socket.io/dist/server'
```js
configuration = {
// Optionally, set here the authentication validation callback (by default server accepts all connections)
// (for example: if client sent a token, you can get token from auth object
authenticate: undefined, // Example: (auth) => auth.token === 'valid-token')
// For example: if client sent a token or other data, you can get it from auth object of
// socket.io handshake
authenticate: undefined, // Example: (handshake) => handshake.auth.token === 'valid-token')
// Optionally, enable LevelDB persistence by setting the directory where you want to store the database (by default the LevelDB persistence is disabled)
levelPersistenceDir: undefined,
// Enable/Disable garbage collection (by default the garbage collection is enabled)
Expand Down
13 changes: 6 additions & 7 deletions examples/react-example/src/App.tsx
Expand Up @@ -5,7 +5,7 @@ import { SocketIOProvider } from 'y-socket.io';
function App() {
const [doc, setDoc] = useState<Y.Doc | null>(null);
const [provider, setProvider] = useState<SocketIOProvider | null>(null);
const [connected, setConnected] = useState<boolean>(true);
const [status, setStatus] = useState<string>('disconnected');
const [input, setInput] = useState<string>('');
const [clients, setClients] = useState<string[]>([]);

Expand Down Expand Up @@ -37,10 +37,9 @@ function App() {
});
socketIOProvider.awareness.on('change', () => setClients(Array.from(socketIOProvider.awareness.getStates().keys()).map(key => `${key}`)))
socketIOProvider.awareness.setLocalState({ id: Math.random(), name: 'Perico' });
socketIOProvider.on('sync', (status: boolean) => console.log('websocket sync', status))
socketIOProvider.on('status', ({ status }: { status: string }) => {
if (status === 'connected') setConnected(true);
else setConnected(false);
socketIOProvider.on('sync', (isSync: boolean) => console.log('websocket sync', isSync))
socketIOProvider.on('status', ({ status: _status }: { status: string }) => {
if (!!_status) setStatus(_status);
})
setProvider(socketIOProvider);
}
Expand All @@ -58,9 +57,9 @@ function App() {
<div>
App
<div style={{ color: 'white' }}>
<p>State: {connected ? 'Connected' : 'Disconneted'}</p>
<p>State: {status}</p>
{
!connected
!(status === 'connected')
? <>
<button onClick={() => provider.connect()}>Connect</button>
</>
Expand Down
2 changes: 1 addition & 1 deletion src/client/provider.ts
Expand Up @@ -242,7 +242,7 @@ export class SocketIOProvider extends Observable<string> {
* Connect provider's socket
* @type {() => void}
*/
public connect (): void {
public connect(): void {
if (!this.socket.connected) {
this.emit('status', [{ status: 'connecting' }])
this.socket.connect()
Expand Down
9 changes: 8 additions & 1 deletion src/server/server.ts
Expand Up @@ -21,7 +21,14 @@ const io = new Server(server)
// for other logic, these do not match the regular expression, this could cause unwanted problems.
// TIP: You can export a new instance from another file to manage as singleton and access documents from all app.
const ysocketio = new YSocketIO(io, {
// authenticate: (auth) => auth.token === 'valid-token',
// authenticate: (handshake) => handshake.auth.token === 'valid-token',
// OR
// authenticate: (handshake) => {
// return new Promise<boolean>(resolve => {
// setTimeout(() => resolve(handshake.auth.token === 'valid-token'), 2000)
// })
// },

// levelPersistenceDir: './storage-location',
// gcEnabled: true,
})
Expand Down
10 changes: 5 additions & 5 deletions src/server/y-socket-io.ts
Expand Up @@ -32,10 +32,10 @@ export interface YSocketIOConfiguration {
/**
* Callback to authenticate the client connection.
*
* If it returns true, the connection is allowed; otherwise, if it returns false, the connection is rejected.
* @param auth Provided from the auth attribute on the socket io handshake
* It can be a promise and if it returns true, the connection is allowed; otherwise, if it returns false, the connection is rejected.
* @param handshake Provided from the handshake attribute of the socket io
*/
authenticate?: (auth: { [key: string]: any }) => boolean
authenticate?: (handshake: { [key: string]: any }) => Promise<boolean> | boolean
}

/**
Expand Down Expand Up @@ -92,9 +92,9 @@ export class YSocketIO extends Observable<string> {
public initialize (): void {
const dynamicNamespace = this.io.of(/^\/yjs\|.*$/)

dynamicNamespace.use((socket, next) => {
dynamicNamespace.use(async (socket, next) => {
if ((this.configuration?.authenticate) == null) return next()
if (this.configuration.authenticate(socket.handshake.auth)) return next()
if (await this.configuration.authenticate(socket.handshake)) return next()
else return next(new Error('Unauthorized'))
})

Expand Down

0 comments on commit 30fc527

Please sign in to comment.