Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
866cec6e
Commit
866cec6e
authored
Nov 02, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more types
parent
f642af8c
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
64 additions
and
127 deletions
+64
-127
useApiSocket.tsx
lib/hooks/useApiSocket.tsx
+0
-103
Socket.ts
lib/socket/Socket.ts
+25
-15
types.ts
lib/socket/types.ts
+19
-4
block.ts
types/api/block.ts
+5
-0
Home.tsx
ui/pages/Home.tsx
+15
-5
No files found.
lib/hooks/useApiSocket.tsx
deleted
100644 → 0
View file @
f642af8c
import
React
from
'
react
'
;
import
{
SECOND
}
from
'
lib/consts
'
;
const
OPEN_STATE
=
1
;
interface
Params
{
onOpen
?:
(
event
:
Event
)
=>
void
;
onError
?:
(
event
:
Event
)
=>
void
;
onClose
?:
(
event
:
Event
)
=>
void
;
}
type
SocketData
=
[
null
,
null
,
string
,
string
,
Record
<
string
,
unknown
>
];
interface
SocketChannelSubscriber
{
filters
?:
Array
<
string
>
;
onMessage
:
(
payload
:
unknown
)
=>
void
;
}
export
default
function
useApiSocket
({
onOpen
,
onError
,
onClose
}:
Params
)
{
const
socket
=
React
.
useRef
<
WebSocket
>
();
const
onReadyEvents
=
React
.
useRef
<
Array
<
SocketData
>>
([]);
const
channels
=
React
.
useRef
<
Record
<
string
,
Array
<
SocketChannelSubscriber
>>>
({});
function
startHeartBeat
()
{
return
window
.
setInterval
(()
=>
{
const
data
:
SocketData
=
[
null
,
null
,
'
phoenix
'
,
'
heartbeat
'
,
{}
];
socket
.
current
?.
send
(
JSON
.
stringify
(
data
));
},
30
*
SECOND
);
}
const
joinRoom
=
React
.
useCallback
((
id
:
string
,
subscriber
:
SocketChannelSubscriber
)
=>
{
const
data
:
SocketData
=
[
null
,
null
,
id
,
'
phx_join
'
,
{}
];
if
(
socket
.
current
?.
readyState
===
OPEN_STATE
)
{
socket
.
current
?.
send
(
JSON
.
stringify
(
data
));
}
else
{
onReadyEvents
.
current
.
push
(
data
);
}
if
(
channels
.
current
[
id
])
{
channels
.
current
[
id
].
push
(
subscriber
);
}
else
{
channels
.
current
[
id
]
=
[
subscriber
];
}
},
[]);
const
leaveRoom
=
React
.
useCallback
((
id
:
string
)
=>
{
const
data
:
SocketData
=
[
null
,
null
,
id
,
'
phx_leave
'
,
{}
];
if
(
socket
.
current
?.
readyState
===
OPEN_STATE
)
{
socket
.
current
?.
send
(
JSON
.
stringify
(
data
));
}
else
{
onReadyEvents
.
current
.
push
(
data
);
}
channels
.
current
[
id
]
=
[];
},
[]);
React
.
useEffect
(()
=>
{
if
(
socket
.
current
)
{
socket
.
current
.
close
();
}
// todo_tom pass host and base path from config
socket
.
current
=
new
WebSocket
(
'
wss://blockscout.com/poa/core/socket/v2/websocket?vsn=2.0.0
'
);
let
heartBeatTimeoutId
:
number
|
undefined
;
socket
.
current
.
addEventListener
(
'
open
'
,
(
event
:
Event
)
=>
{
onOpen
?.(
event
);
heartBeatTimeoutId
=
startHeartBeat
();
onReadyEvents
.
current
.
forEach
((
data
)
=>
socket
.
current
?.
send
(
JSON
.
stringify
(
data
)));
onReadyEvents
.
current
=
[];
});
socket
.
current
.
addEventListener
(
'
message
'
,
(
event
)
=>
{
const
data
:
SocketData
=
JSON
.
parse
(
event
.
data
);
const
channelId
=
data
[
2
];
const
filterId
=
data
[
3
];
const
payload
=
data
[
4
];
const
subscribers
=
channels
.
current
[
channelId
];
subscribers
?.
filter
((
subscriber
)
=>
subscriber
.
filters
?
subscriber
.
filters
.
includes
(
filterId
)
:
true
)
?.
forEach
((
subscriber
)
=>
subscriber
.
onMessage
(
payload
));
});
socket
.
current
.
addEventListener
(
'
error
'
,
(
event
)
=>
{
onError
?.(
event
);
});
socket
.
current
.
addEventListener
(
'
close
'
,
(
event
)
=>
{
onClose
?.(
event
);
});
return
()
=>
{
window
.
clearInterval
(
heartBeatTimeoutId
);
socket
.
current
?.
close
();
};
},
[
onClose
,
onError
,
onOpen
]);
return
{
joinRoom
,
leaveRoom
};
}
lib/socket/Socket.ts
View file @
866cec6e
import
type
{
SocketData
,
Socket
Channel
Subscriber
}
from
'
lib/socket/types
'
;
import
type
{
SocketData
,
SocketSubscriber
}
from
'
lib/socket/types
'
;
import
appConfig
from
'
configs/app/config
'
;
import
{
SECOND
}
from
'
lib/consts
'
;
...
...
@@ -15,9 +15,9 @@ class Socket {
private
socket
:
WebSocket
|
undefined
;
private
heartBeatIntervalId
:
number
|
undefined
;
private
onReadyEvents
:
Array
<
SocketData
>
=
[];
private
channels
:
Record
<
string
,
Array
<
Socket
Channel
Subscriber
>>
=
{};
private
channels
:
Record
<
string
,
Array
<
SocketSubscriber
>>
=
{};
init
({
onOpen
,
onError
,
onClose
}:
InitParams
)
{
init
({
onOpen
,
onError
,
onClose
}:
InitParams
|
undefined
=
{}
)
{
if
(
this
.
socket
)
{
return
this
;
}
...
...
@@ -36,12 +36,13 @@ class Socket {
const
data
:
SocketData
=
JSON
.
parse
(
event
.
data
);
const
channelId
=
data
[
2
];
const
filter
Id
=
data
[
3
];
const
event
Id
=
data
[
3
];
const
payload
=
data
[
4
];
const
subscribers
=
this
.
channels
[
channelId
];
subscribers
?.
filter
((
subscriber
)
=>
subscriber
.
filters
?
subscriber
.
filters
.
includes
(
filterId
)
:
true
)
?.
forEach
((
subscriber
)
=>
subscriber
.
onMessage
(
payload
));
?.
filter
((
subscriber
)
=>
subscriber
.
eventId
?
subscriber
.
eventId
===
eventId
:
true
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
?.
forEach
((
subscriber
)
=>
subscriber
.
onMessage
(
payload
as
any
));
});
this
.
socket
.
addEventListener
(
'
error
'
,
(
event
)
=>
{
...
...
@@ -63,8 +64,9 @@ class Socket {
this
.
channels
=
{};
}
joinRoom
(
id
:
string
,
subscriber
:
SocketChannelSubscriber
)
{
const
data
:
SocketData
=
[
null
,
null
,
id
,
'
phx_join
'
,
{}
];
joinRoom
(
subscriber
:
SocketSubscriber
)
{
const
channelId
=
this
.
getChannelId
(
subscriber
.
channelId
,
subscriber
.
hash
);
const
data
:
SocketData
=
[
null
,
null
,
channelId
,
'
phx_join
'
,
{}
];
if
(
this
.
socket
?.
readyState
===
OPEN_STATE
)
{
this
.
socket
?.
send
(
JSON
.
stringify
(
data
));
...
...
@@ -72,16 +74,16 @@ class Socket {
this
.
onReadyEvents
.
push
(
data
);
}
if
(
this
.
channels
[
i
d
])
{
this
.
channels
[
i
d
].
push
(
subscriber
);
if
(
this
.
channels
[
channelI
d
])
{
this
.
channels
[
channelI
d
].
push
(
subscriber
);
}
else
{
this
.
channels
[
i
d
]
=
[
subscriber
];
this
.
channels
[
channelI
d
]
=
[
subscriber
];
}
}
leaveRoom
(
id
:
string
)
{
// todo_tom remove only specified subscriber
const
data
:
SocketData
=
[
null
,
null
,
i
d
,
'
phx_leave
'
,
{}
];
leaveRoom
(
subscriber
:
SocketSubscriber
)
{
const
channelId
=
this
.
getChannelId
(
subscriber
.
channelId
,
subscriber
.
hash
);
const
data
:
SocketData
=
[
null
,
null
,
channelI
d
,
'
phx_leave
'
,
{}
];
if
(
this
.
socket
?.
readyState
===
OPEN_STATE
)
{
this
.
socket
?.
send
(
JSON
.
stringify
(
data
));
...
...
@@ -89,7 +91,7 @@ class Socket {
this
.
onReadyEvents
.
push
(
data
);
}
this
.
channels
[
id
]
=
[]
;
this
.
channels
[
channelId
]?.
filter
(({
onMessage
})
=>
onMessage
!==
subscriber
.
onMessage
)
;
}
private
startHeartBeat
()
{
...
...
@@ -98,6 +100,14 @@ class Socket {
this
.
socket
?.
send
(
JSON
.
stringify
(
data
));
},
30
*
SECOND
);
}
private
getChannelId
(
pattern
:
string
,
hash
?:
string
)
{
if
(
!
hash
)
{
return
pattern
;
}
return
pattern
.
replace
(
'
[hash]
'
,
hash
);
}
}
export
default
Socket
;
lib/socket/types.ts
View file @
866cec6e
export
type
SocketData
=
[
null
,
null
,
string
,
string
,
Record
<
string
,
unknown
>
]
;
import
type
{
NewBlockSocketResponse
}
from
'
types/api/block
'
;
export
interface
SocketChannelSubscriber
{
filters
?:
Array
<
string
>
;
onMessage
:
(
payload
:
unknown
)
=>
void
;
export
type
SocketData
=
[
null
,
null
,
string
,
string
,
unknown
];
export
type
SocketSubscriber
=
SocketSubscribers
.
BlocksNewBlock
|
SocketSubscribers
.
BlocksIndexStatus
|
SocketSubscribers
.
BlockNewBlock
;
interface
SocketSubscriberGeneric
<
Channel
extends
string
,
Event
extends
string
,
Payload
>
{
channelId
:
Channel
;
eventId
:
Event
;
onMessage
:
(
payload
:
Payload
)
=>
void
;
hash
?:
string
;
}
// eslint-disable-next-line @typescript-eslint/no-namespace
export
namespace
SocketSubscribers
{
export
type
BlocksNewBlock
=
SocketSubscriberGeneric
<
'
blocks:new_block
'
,
'
new_block
'
,
NewBlockSocketResponse
>
;
export
type
BlocksIndexStatus
=
SocketSubscriberGeneric
<
'
blocks:indexing
'
,
'
index_status
'
,
{
finished
:
boolean
;
ratio
:
string
}
>
;
export
type
BlockNewBlock
=
SocketSubscriberGeneric
<
'
blocks:[hash]
'
,
'
new_block
'
,
NewBlockSocketResponse
>
;
}
types/api/block.ts
View file @
866cec6e
...
...
@@ -47,3 +47,8 @@ export interface BlockTransactionsResponse {
items_count
:
number
;
}
|
null
;
}
export
interface
NewBlockSocketResponse
{
average_block_time
:
string
;
block
:
Block
;
}
ui/pages/Home.tsx
View file @
866cec6e
...
...
@@ -3,6 +3,8 @@ import * as Sentry from '@sentry/react';
import
type
{
ChangeEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SocketSubscribers
}
from
'
lib/socket/types
'
;
import
appConfig
from
'
configs/app/config
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
...
...
@@ -17,14 +19,22 @@ const Home = () => {
const
[
token
,
setToken
]
=
React
.
useState
(
''
);
React
.
useEffect
(()
=>
{
const
socket
=
(
new
Socket
).
init
({});
socket
.
joinRoom
(
'
blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252
'
,
{
filters
:
[
'
new_block
'
],
onMessage
:
()
=>
{},
const
socket
=
(
new
Socket
).
init
();
const
onMessage
:
SocketSubscribers
.
BlocksNewBlock
[
'
onMessage
'
]
=
()
=>
{};
socket
.
joinRoom
({
channelId
:
'
blocks:new_block
'
,
eventId
:
'
new_block
'
,
onMessage
,
hash
:
'
0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252
'
,
});
return
()
=>
{
socket
.
leaveRoom
(
'
blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252
'
);
socket
.
leaveRoom
({
channelId
:
'
blocks:[hash]
'
,
eventId
:
'
new_block
'
,
hash
:
'
0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252
'
,
onMessage
,
});
socket
.
close
();
};
},
[]);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment