mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-13 20:04:35 +03:00
herm: userspace dill proxy
Listens to the default dill session and passes its %blits on to subscribers. Passes any %belt pokes it gets into dill. Updates webdojo to make use of it, which is the primary motivation for herm's existence.
This commit is contained in:
parent
83d46dae88
commit
185b553c99
61
pkg/arvo/app/herm.hoon
Normal file
61
pkg/arvo/app/herm.hoon
Normal file
@ -0,0 +1,61 @@
|
||||
:: herm: stand-in for term.c with http interface
|
||||
::
|
||||
/+ default-agent, dbug, verb
|
||||
=, able:jael
|
||||
|%
|
||||
+$ state-0 [%0 ~]
|
||||
--
|
||||
::
|
||||
=| state-0
|
||||
=* state -
|
||||
%+ verb |
|
||||
%- agent:dbug
|
||||
^- agent:gall
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init
|
||||
^- (quip card:agent:gall _this)
|
||||
:_ this
|
||||
[%pass /herm/1 %arvo %d %view [//term/1]~]~
|
||||
::
|
||||
++ on-save !>([%0 ~])
|
||||
++ on-load
|
||||
|= old=vase
|
||||
^- (quip card:agent:gall _this)
|
||||
[~ this(state [%0 ~])]
|
||||
::
|
||||
++ on-watch
|
||||
|= =path
|
||||
^- (quip card:agent:gall _this)
|
||||
?. ?=([%herm ~] path) !!
|
||||
[~ this]
|
||||
::
|
||||
++ on-arvo
|
||||
|= [=wire =sign-arvo]
|
||||
^- (quip card:agent:gall _this)
|
||||
?. =(/herm/1 wire) !!
|
||||
?. ?=([%d %blit *] sign-arvo)
|
||||
~| [%unexpected-sign [- +<]:sign-arvo]
|
||||
!!
|
||||
:: ~& [dap.bowl %blit (turn p.sign-arvo head)]
|
||||
:_ this
|
||||
%+ turn p.sign-arvo
|
||||
|= =blit:dill
|
||||
[%give %fact [/herm]~ %blit !>(blit)]
|
||||
::
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card:agent:gall _this)
|
||||
?. ?=(%belt mark)
|
||||
~| [%unexpected-mark mark]
|
||||
!!
|
||||
:_ this
|
||||
[%pass /herm/1 %arvo %d %belt !<(belt:dill vase)]~
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
++ on-peek on-peek:def
|
||||
++ on-agent on-agent:def
|
||||
++ on-fail on-fail:def
|
||||
--
|
32
pkg/arvo/mar/belt.hoon
Normal file
32
pkg/arvo/mar/belt.hoon
Normal file
@ -0,0 +1,32 @@
|
||||
:: belt: runtime belt structure
|
||||
::
|
||||
~% %mar-belt ..is ~
|
||||
|_ =belt:dill
|
||||
++ grad %noun
|
||||
:: +grab: convert from
|
||||
::
|
||||
++ grab
|
||||
~% %belt-grab ..grab ~
|
||||
|%
|
||||
++ noun belt:dill
|
||||
++ json
|
||||
~/ %mar-belt-json
|
||||
^- $-(^json belt:dill)
|
||||
=, dejs:format
|
||||
%- of
|
||||
:~ aro+(su (perk %d %l %r %u ~))
|
||||
bac+ul
|
||||
ctl+`$-(json @c)`so
|
||||
del+ul
|
||||
met+`$-(json @c)`so
|
||||
ret+ul
|
||||
txt+`$-(json (list @c))`sa
|
||||
==
|
||||
--
|
||||
:: +grow: convert to
|
||||
::
|
||||
++ grow
|
||||
|%
|
||||
++ noun belt
|
||||
--
|
||||
--
|
48
pkg/arvo/mar/blit.hoon
Normal file
48
pkg/arvo/mar/blit.hoon
Normal file
@ -0,0 +1,48 @@
|
||||
:: blit: runtime blit structure
|
||||
::
|
||||
~% %mar-blit ..is ~
|
||||
|_ =blit:dill
|
||||
++ grad %noun
|
||||
:: +grab: convert from
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun blit:dill
|
||||
--
|
||||
:: +grow: convert to
|
||||
::
|
||||
++ grow
|
||||
~% %blit-grow ..grow ~
|
||||
|%
|
||||
++ noun blit
|
||||
++ json
|
||||
^- ^json
|
||||
=, enjs:format
|
||||
%+ frond -.blit
|
||||
?- -.blit
|
||||
%bel b+&
|
||||
%clr b+&
|
||||
%hop (numb p.blit)
|
||||
%lin s+(crip (tufa p.blit))
|
||||
%mor b+&
|
||||
%sag (pairs 'path'^(path p.blit) 'file'^s+(jam q.blit) ~)
|
||||
%sav (pairs 'path'^(path p.blit) 'file'^s+q.blit ~)
|
||||
%url s+p.blit
|
||||
::
|
||||
%klr
|
||||
:- %a
|
||||
%+ turn p.blit
|
||||
|= [=stye text=(list @c)]
|
||||
%- pairs
|
||||
:~ 'text'^s+(crip (tufa text))
|
||||
::
|
||||
:- 'stye'
|
||||
%- pairs
|
||||
:~ 'back'^[?~(. ~ s+.)]:p.q.stye
|
||||
'fore'^[?~(. ~ s+.)]:q.q.stye
|
||||
'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d)))
|
||||
==
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
@ -29,8 +29,8 @@ export default class Api {
|
||||
});
|
||||
}
|
||||
|
||||
soto(data) {
|
||||
return this.action('dojo', 'sole-action', { id: this.dojoId, dat: data });
|
||||
belt(belt) {
|
||||
return this.action('herm', 'belt', belt);
|
||||
}
|
||||
|
||||
action(appl, mark, data) {
|
||||
|
@ -72,14 +72,13 @@ export default class DojoApp extends Component {
|
||||
cursor: 'text'
|
||||
}}
|
||||
>
|
||||
<History commandLog={this.state.txt} />
|
||||
<History log={this.state.lines.slice(0, -1)} />
|
||||
<Input
|
||||
ship={this.props.ship}
|
||||
cursor={this.state.cursor}
|
||||
prompt={this.state.prompt}
|
||||
input={this.state.input}
|
||||
api={this.api}
|
||||
store={this.store}
|
||||
line={this.state.lines.slice(-1)[0]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Line from './line';
|
||||
|
||||
export class History extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -12,14 +14,8 @@ export class History extends Component {
|
||||
style={{ resize: 'none' }}
|
||||
>
|
||||
<div style={{ marginTop: 'auto' }}>
|
||||
{this.props.commandLog.map((text, index) => {
|
||||
return (
|
||||
<p className="mono" key={index}
|
||||
style={{ overflowWrap: 'break-word', whiteSpace: 'pre' }}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
);
|
||||
{this.props.log.map((line, i) => {
|
||||
return <Line key={i} index={i} line={line} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@ export class Input extends Component {
|
||||
type: 'Sending to Dojo'
|
||||
};
|
||||
this.keyPress = this.keyPress.bind(this);
|
||||
this.click = this.click.bind(this);
|
||||
this.inputRef = React.createRef();
|
||||
}
|
||||
|
||||
@ -24,64 +25,70 @@ export class Input extends Component {
|
||||
}
|
||||
|
||||
keyPress(e) {
|
||||
let key = e.key;
|
||||
// let paste event pass
|
||||
if ((e.getModifierState('Control') || event.getModifierState('Meta'))
|
||||
&& e.key === 'v') {
|
||||
&& e.key === 'v') {
|
||||
return;
|
||||
}
|
||||
|
||||
let belt = null;
|
||||
if (key === 'ArrowLeft') belt = {aro: 'l'};
|
||||
else if (key === 'ArrowRight') belt = {aro: 'r'};
|
||||
else if (key === 'ArrowUp') belt = {aro: 'u'};
|
||||
else if (key === 'ArrowDown') belt = {aro: 'd'};
|
||||
else if (key === 'Backspace') belt = {bac: null};
|
||||
else if (key === 'Delete') belt = {del: null};
|
||||
else if (key === 'Tab') belt = {ctl: 'i'};
|
||||
else if (key === 'Enter') belt = {ret: null};
|
||||
else if (key.length === 1) belt = {txt: key};
|
||||
else belt = null;
|
||||
|
||||
if (belt && e.getModifierState('Control')) {
|
||||
if (belt.txt !== undefined) belt = {ctl: belt.txt};
|
||||
} else
|
||||
if (belt &&
|
||||
(e.getModifierState('Meta') || e.getModifierState('Alt'))) {
|
||||
if (belt.bac !== undefined) belt = {met: 'bac'};
|
||||
}
|
||||
|
||||
if (belt !== null) {
|
||||
this.props.api.belt(belt);
|
||||
}
|
||||
|
||||
//TODO handle paste
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const allowedKeys = [
|
||||
'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab'
|
||||
];
|
||||
}
|
||||
|
||||
if ((e.key.length > 1) && (!(allowedKeys.includes(e.key)))) {
|
||||
return;
|
||||
}
|
||||
paste(e) {
|
||||
const clipboardData = e.clipboardData || window.clipboardData;
|
||||
this.props.api.belt({ txt: clipboardData.getData('Text') });
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// submit on enter
|
||||
if (e.key === 'Enter') {
|
||||
this.setState({ awaiting: true, type: 'Sending to Dojo' });
|
||||
this.props.api.soto('ret').then(() => {
|
||||
this.setState({ awaiting: false });
|
||||
});
|
||||
} else if ((e.key === 'Backspace') && (this.props.cursor > 0)) {
|
||||
this.props.store.doEdit({ del: this.props.cursor - 1 });
|
||||
return this.props.store.setState({ cursor: this.props.cursor - 1 });
|
||||
} else if (e.key === 'Backspace') {
|
||||
return;
|
||||
} else if (e.key.startsWith('Arrow')) {
|
||||
if (e.key === 'ArrowLeft') {
|
||||
if (this.props.cursor > 0) {
|
||||
this.props.store.setState({ cursor: this.props.cursor - 1 });
|
||||
}
|
||||
} else if (e.key === 'ArrowRight') {
|
||||
if (this.props.cursor < this.props.input.length) {
|
||||
this.props.store.setState({ cursor: this.props.cursor + 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tab completion
|
||||
else if (e.key === 'Tab') {
|
||||
this.setState({ awaiting: true, type: 'Getting suggestions' });
|
||||
this.props.api.soto({ tab: this.props.cursor }).then(() => {
|
||||
this.setState({ awaiting: false });
|
||||
});
|
||||
}
|
||||
|
||||
// capture and transmit most characters
|
||||
else {
|
||||
this.props.store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
|
||||
this.props.store.setState({ cursor: this.props.cursor + 1 });
|
||||
}
|
||||
click(e) {
|
||||
// prevent desynced cursor movement
|
||||
e.preventDefault();
|
||||
e.target.setSelectionRange(this.props.cursor, this.props.cursor);
|
||||
}
|
||||
|
||||
render() {
|
||||
const line = this.props.line;
|
||||
let prompt = 'connecting...';
|
||||
if (line) {
|
||||
if (line.lin) {
|
||||
prompt = line.lin;
|
||||
}
|
||||
//TODO render prompt style
|
||||
else if (line.klr) {
|
||||
prompt = line.klr.reduce((l, p) => (l + p), '');
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-row flex-grow-1 relative">
|
||||
<div className="flex-shrink-0"><span class="dn-s">{cite(this.props.ship)}:</span>dojo
|
||||
</div>
|
||||
<div className="flex-shrink-0"></div>
|
||||
<span id="prompt">
|
||||
{this.props.prompt}
|
||||
</span>
|
||||
@ -95,22 +102,13 @@ export class Input extends Component {
|
||||
className="mono ml1 flex-auto dib w-100"
|
||||
id="dojo"
|
||||
cursor={this.props.cursor}
|
||||
onClick={e => this.props.store.setState({ cursor: e.target.selectionEnd })}
|
||||
onKeyDown={this.keyPress}
|
||||
onPaste={(e) => {
|
||||
const clipboardData = e.clipboardData || window.clipboardData;
|
||||
const paste = Array.from(clipboardData.getData('Text'));
|
||||
paste.reduce(async (previous, next) => {
|
||||
await previous;
|
||||
this.setState({ cursor: this.props.cursor + 1 });
|
||||
return this.props.store.doEdit({ ins: { cha: next, at: this.props.cursor } });
|
||||
}, Promise.resolve());
|
||||
e.preventDefault();
|
||||
}}
|
||||
onClick={this.click}
|
||||
onPaste={this.paste}
|
||||
ref={this.inputRef}
|
||||
defaultValue={this.props.input}
|
||||
defaultValue="connecting..."
|
||||
value={prompt}
|
||||
/>
|
||||
<Spinner awaiting={this.state.awaiting} text={`${this.state.type}...`} classes="absolute right-0 bottom-0 inter pa ba pa2 b--gray1-d" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
66
pkg/interface/src/views/apps/dojo/components/line.js
Normal file
66
pkg/interface/src/views/apps/dojo/components/line.js
Normal file
@ -0,0 +1,66 @@
|
||||
import React, { Component, useMemo } from 'react';
|
||||
import { Box, Text } from '@tlon/indigo-react';
|
||||
|
||||
export default function Line({index, line}) {
|
||||
const out = useMemo(() => {
|
||||
let text = '';
|
||||
if (line.lin) {
|
||||
text = line.lin;
|
||||
}
|
||||
else if (line.klr) {
|
||||
text = line.klr.map((part, i) => {
|
||||
let prop = part.stye.deco.reduce((prop, deco) => {
|
||||
switch (deco) {
|
||||
case null: return prop;
|
||||
case 'br': return {bold: true, ...prop};
|
||||
case 'bl': return {blink: true, ...prop}; //TODO
|
||||
case 'un': return {textDecoration: 'underline', ...prop}; //TODO fixme
|
||||
default: console.log('weird deco', deco); return prop;
|
||||
}
|
||||
}, {});
|
||||
switch (part.stye.fore) {
|
||||
case null: break;
|
||||
case 'r': prop.color = 'red'; break;
|
||||
case 'g': prop.color = 'green'; break;
|
||||
case 'b': prop.color = 'blue'; break;
|
||||
case 'c': prop.color = 'cyan'; break;
|
||||
case 'm': prop.color = 'purple'; break;
|
||||
case 'y': prop.color = 'yellow'; break;
|
||||
case 'k': prop.color = 'black'; break;
|
||||
case 'w': prop.color = 'white'; break;
|
||||
default: console.log('weird fore', part.stye.fore);
|
||||
}
|
||||
switch (part.stye.back) {
|
||||
case null: break;
|
||||
case 'r': prop.backgroundColor = 'red'; break;
|
||||
case 'g': prop.backgroundColor = 'green'; break;
|
||||
case 'b': prop.backgroundColor = 'blue'; break;
|
||||
case 'c': prop.backgroundColor = 'cyan'; break;
|
||||
case 'm': prop.backgroundColor = 'purple'; break;
|
||||
case 'y': prop.backgroundColor = 'yellow'; break;
|
||||
case 'k': prop.backgroundColor = 'black'; break;
|
||||
case 'w': prop.backgroundColor = 'white'; break;
|
||||
default: console.log('weird back', part.stye.back);
|
||||
}
|
||||
if (Object.keys(prop).length === 0)
|
||||
{
|
||||
return part.text;
|
||||
} else {
|
||||
return (<Text mono fontSize='inherit' key={index+'-'+i} {...prop}>{part.text}</Text>);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// render line
|
||||
//
|
||||
return (
|
||||
<Text mono display='block' fontSize='14px'
|
||||
style={{ overflowWrap: 'break-word', whiteSpace: 'pre' }}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
);
|
||||
}, [line, index]);
|
||||
|
||||
return out;
|
||||
}
|
@ -2,92 +2,55 @@ import Share from './components/lib/sole';
|
||||
export default class Store {
|
||||
constructor() {
|
||||
this.state = this.initialState();
|
||||
this.sync = this.sync.bind(this);
|
||||
this.print = this.print.bind(this);
|
||||
this.buffer = new Share();
|
||||
}
|
||||
|
||||
initialState() {
|
||||
return {
|
||||
txt: [],
|
||||
prompt: '',
|
||||
lines: [''],
|
||||
cursor: 0,
|
||||
input: ''
|
||||
};
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.handleEvent({
|
||||
data: { clear: true }
|
||||
});
|
||||
this.setState(this.initialState())
|
||||
}
|
||||
|
||||
handleEvent(data) {
|
||||
// recursive handler
|
||||
if (data.data) {
|
||||
var dojoReply = data.data;
|
||||
} else {
|
||||
var dojoReply = data;
|
||||
}
|
||||
const blit = data.data;
|
||||
|
||||
if (dojoReply.clear) {
|
||||
this.setState(this.initialState(), (() => {
|
||||
return;
|
||||
}));
|
||||
}
|
||||
|
||||
// %mor sole-effects are nested, so throw back to handler
|
||||
if (dojoReply.map) {
|
||||
return dojoReply.map(reply => this.handleEvent(reply));
|
||||
}
|
||||
|
||||
switch (Object.keys(dojoReply)[0]) {
|
||||
case 'txt':
|
||||
return this.print(dojoReply.txt);
|
||||
case 'tab':
|
||||
this.print(dojoReply.tab.match + ' ' + dojoReply.tab.info);
|
||||
return;
|
||||
case 'tan':
|
||||
return dojoReply.tan.split('\n').map(this.print);
|
||||
case 'pro':
|
||||
return this.setState({ prompt: dojoReply.pro.cad });
|
||||
case 'hop':
|
||||
return this.setState({ cursor: dojoReply.hop });
|
||||
case 'det':
|
||||
this.buffer.receive(dojoReply.det);
|
||||
return this.sync(dojoReply.det.ted);
|
||||
case 'act':
|
||||
switch (dojoReply.act) {
|
||||
case 'clr': return this.setState({ txt: [] });
|
||||
case 'nex': return this.setState({
|
||||
input: '',
|
||||
cursor: 0
|
||||
});
|
||||
}
|
||||
switch (Object.keys(blit)[0]) {
|
||||
case 'bel':
|
||||
let beep = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
|
||||
beep.play();
|
||||
break;
|
||||
default: console.log(dojoReply);
|
||||
case 'clr':
|
||||
this.setState({ lines: [''] });
|
||||
break;
|
||||
case 'hop':
|
||||
this.setState({ cursor: blit.hop });
|
||||
break;
|
||||
case 'lin':
|
||||
this.state.lines[this.state.lines.length - 1] = blit;
|
||||
this.setState({ lines: this.state.lines });
|
||||
break;
|
||||
case 'klr':
|
||||
this.state.lines[this.state.lines.length - 1] = blit;
|
||||
this.setState({ lines: this.state.lines });
|
||||
break;
|
||||
case 'mor':
|
||||
this.state.lines.push('');
|
||||
this.setState({ lines: this.state.lines });
|
||||
break;
|
||||
//TODO file downloads for %sag and %sav
|
||||
case 'url':
|
||||
//TODO too invasive? just print as <a>?
|
||||
window.open(blit.url);
|
||||
break;
|
||||
default: console.log('weird blit', blit);
|
||||
}
|
||||
}
|
||||
|
||||
doEdit(ted) {
|
||||
const detSend = this.buffer.transmit(ted);
|
||||
this.sync(ted);
|
||||
return this.api.soto({ det: detSend });
|
||||
}
|
||||
|
||||
print(txt) {
|
||||
const textLog = this.state.txt;
|
||||
textLog.push(txt);
|
||||
return this.setState({ txt: textLog });
|
||||
}
|
||||
|
||||
sync(ted) {
|
||||
return this.setState({
|
||||
input: this.buffer.buf,
|
||||
cursor: this.buffer.transpose(ted, this.state.cursor)
|
||||
});
|
||||
}
|
||||
|
||||
setStateHandler(setState) {
|
||||
this.setState = setState;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export default class Subscription {
|
||||
}
|
||||
|
||||
firstRound() {
|
||||
this.subscribe('/sole/' + this.api.dojoId, 'dojo');
|
||||
this.subscribe('/herm', 'herm');
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
|
Loading…
Reference in New Issue
Block a user