ngx-kel-agent 0.4.9 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -26
- package/esm2020/lib/agent-message.service.mjs +18 -0
- package/esm2020/lib/agent.service.mjs +91 -187
- package/esm2020/lib/hamlib-messages.mjs +2 -0
- package/esm2020/lib/hamlib.service.mjs +48 -0
- package/esm2020/lib/wsjtx-messages.mjs +2 -0
- package/esm2020/lib/wsjtx.service.mjs +247 -0
- package/esm2020/public-api.mjs +8 -2
- package/fesm2015/ngx-kel-agent.mjs +362 -166
- package/fesm2015/ngx-kel-agent.mjs.map +1 -1
- package/fesm2020/ngx-kel-agent.mjs +361 -159
- package/fesm2020/ngx-kel-agent.mjs.map +1 -1
- package/lib/agent-message.service.d.ts +9 -0
- package/lib/agent.service.d.ts +113 -28
- package/lib/hamlib-messages.d.ts +10 -0
- package/lib/hamlib.service.d.ts +16 -0
- package/lib/{messages.d.ts → wsjtx-messages.d.ts} +4 -12
- package/lib/wsjtx.service.d.ts +62 -0
- package/package.json +4 -4
- package/public-api.d.ts +5 -1
- package/esm2020/lib/messages.mjs +0 -2
|
@@ -1,244 +1,162 @@
|
|
|
1
|
+
import { Subject, BehaviorSubject, ReplaySubject } from 'rxjs';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
3
|
import { Injectable } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';
|
|
4
4
|
import { debounceTime, retryWhen, tap, delay } from 'rxjs/operators';
|
|
5
5
|
import { webSocket } from 'rxjs/webSocket';
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class AgentMessageService {
|
|
8
8
|
constructor() {
|
|
9
|
-
|
|
10
|
-
this.
|
|
11
|
-
|
|
9
|
+
this.rxMessage$ = new Subject();
|
|
10
|
+
this.txMessage$ = new Subject();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
AgentMessageService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentMessageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
14
|
+
AgentMessageService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentMessageService, providedIn: 'root' });
|
|
15
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentMessageService, decorators: [{
|
|
16
|
+
type: Injectable,
|
|
17
|
+
args: [{
|
|
18
|
+
providedIn: 'root',
|
|
19
|
+
}]
|
|
20
|
+
}], ctorParameters: function () { return []; } });
|
|
21
|
+
|
|
22
|
+
class WsjtxService {
|
|
23
|
+
constructor(messages) {
|
|
24
|
+
this.messages = messages;
|
|
12
25
|
/** Whether we're getting any messages from WSJT-X. */
|
|
13
|
-
this.
|
|
26
|
+
this.connected$ = new BehaviorSubject(false);
|
|
14
27
|
/** Subject for listening to WSJT-X "Heartbeat" messages. */
|
|
15
|
-
this.
|
|
28
|
+
this.heartbeat$ = new ReplaySubject(1);
|
|
16
29
|
/** Subject for listening to WSJT-X "Status" messages. */
|
|
17
|
-
this.
|
|
30
|
+
this.status$ = new ReplaySubject(1);
|
|
18
31
|
/** Subject for listening to WSJT-X "Decode" messages. */
|
|
19
|
-
this.
|
|
32
|
+
this.decode$ = new Subject();
|
|
20
33
|
/** Subject for listening to WSJT-X "Clear" messages. */
|
|
21
|
-
this.
|
|
34
|
+
this.clear$ = new Subject();
|
|
22
35
|
/** Subject for listening to WSJT-X "QsoLogged" messages. */
|
|
23
|
-
this.
|
|
36
|
+
this.qsoLogged$ = new Subject();
|
|
24
37
|
/** Subject for listening to WSJT-X "Close" messages. */
|
|
25
|
-
this.
|
|
38
|
+
this.close$ = new Subject();
|
|
26
39
|
/** Subject for listening to WSJT-X "WsprDecode" messages. */
|
|
27
|
-
this.
|
|
40
|
+
this.wsprDecode$ = new Subject();
|
|
28
41
|
/** Subject for listening to WSJT-X "LoggedAdif" messages. */
|
|
29
|
-
this.
|
|
30
|
-
/* Hamlib */
|
|
31
|
-
/** Whether we're getting any messages from Hamlib. */
|
|
32
|
-
this.hamlibState$ = new BehaviorSubject(false);
|
|
33
|
-
/** Subject for listening to Hamlib "RigState" messages. */
|
|
34
|
-
this.hamlibRigState$ = new BehaviorSubject(null);
|
|
35
|
-
this.defaultAgentHost = 'localhost';
|
|
36
|
-
this.defaultAgentPort = 8081;
|
|
37
|
-
this.localStorageHostKey = 'agent-host';
|
|
38
|
-
this.localStoragePortKey = 'agent-port';
|
|
39
|
-
this.agentHost = this.defaultAgentHost;
|
|
40
|
-
this.agentPort = this.defaultAgentPort;
|
|
41
|
-
this.agentWebSocketSubject = null;
|
|
42
|
-
this.agentWebsocketSubscription = null;
|
|
42
|
+
this.loggedAdif$ = new Subject();
|
|
43
43
|
this.wsjtxId = 'WSJT-X';
|
|
44
|
+
this.setupBehaviors();
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
-
this.
|
|
47
|
-
this.agentPort = this.getPort();
|
|
48
|
-
this.setupWsjtxBehaviors();
|
|
49
|
-
this.setupHamlibBehaviors();
|
|
50
|
-
this.connect();
|
|
51
|
-
}
|
|
52
|
-
setupWsjtxBehaviors() {
|
|
46
|
+
setupBehaviors() {
|
|
47
|
+
this.messages.rxMessage$.subscribe((msg) => this.handleMessage(msg));
|
|
53
48
|
// if we haven't heard from WSJT-X in 15 seconds, consider it "down"
|
|
54
|
-
this.
|
|
49
|
+
this.connected$
|
|
55
50
|
.pipe(debounceTime(15000))
|
|
56
|
-
.subscribe(() => this.
|
|
51
|
+
.subscribe(() => this.connected$.next(false));
|
|
57
52
|
// When WSJT-X announces it's closing, set it to "down" immediately
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
53
|
+
this.close$.subscribe(() => {
|
|
54
|
+
this.connected$.next(false);
|
|
60
55
|
});
|
|
61
56
|
// When WSJT-X goes down, clear its persistent message subjects
|
|
62
|
-
this.
|
|
63
|
-
if (!isUp) {
|
|
64
|
-
this.wsjtxHeartbeat$.next(null);
|
|
65
|
-
this.wsjtxStatus$.next(null);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
setupHamlibBehaviors() {
|
|
70
|
-
// if we haven't heard from Hamlib in 15 seconds, consider it down
|
|
71
|
-
this.hamlibState$.pipe(debounceTime(15000)).subscribe(() => {
|
|
72
|
-
this.hamlibState$.next(false);
|
|
73
|
-
});
|
|
74
|
-
// When Hamlib goes down, clear its persistent message subjects
|
|
75
|
-
this.hamlibState$.subscribe((isUp) => {
|
|
57
|
+
this.connected$.subscribe((isUp) => {
|
|
76
58
|
if (!isUp) {
|
|
77
|
-
this.
|
|
59
|
+
this.heartbeat$.next(null);
|
|
60
|
+
this.status$.next(null);
|
|
78
61
|
}
|
|
79
62
|
});
|
|
80
63
|
}
|
|
81
|
-
/** Connect (or reconnect) the websocket to the kel-agent server. */
|
|
82
|
-
connect() {
|
|
83
|
-
if (this.agentWebsocketSubscription) {
|
|
84
|
-
this.agentWebsocketSubscription.unsubscribe();
|
|
85
|
-
}
|
|
86
|
-
this.agentHost = this.getHost();
|
|
87
|
-
this.agentPort = this.getPort();
|
|
88
|
-
const protocol = this.agentHost === 'localhost' ? 'ws://' : 'wss://';
|
|
89
|
-
this.agentWebSocketSubject = webSocket({
|
|
90
|
-
url: protocol + this.agentHost + ':' + this.agentPort + '/websocket',
|
|
91
|
-
});
|
|
92
|
-
this.connectedState$.next(true);
|
|
93
|
-
this.agentWebsocketSubscription = this.agentWebSocketSubject
|
|
94
|
-
.pipe(retryWhen((errors) =>
|
|
95
|
-
// retry the websocket connection after 10 seconds
|
|
96
|
-
errors.pipe(tap(() => this.connectedState$.next(false)), delay(10000))))
|
|
97
|
-
.subscribe({
|
|
98
|
-
next: (msg) => {
|
|
99
|
-
this.connectedState$.next(true);
|
|
100
|
-
this.handleMessage(msg);
|
|
101
|
-
},
|
|
102
|
-
error: () => this.connectedState$.next(false),
|
|
103
|
-
complete: () => this.connectedState$.next(false),
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
64
|
handleMessage(msg) {
|
|
107
|
-
if (msg.wsjtx
|
|
108
|
-
|
|
109
|
-
this.wsjtxId = msg.wsjtx.payload.id;
|
|
110
|
-
switch (msg.wsjtx.type) {
|
|
111
|
-
case 'HeartbeatMessage':
|
|
112
|
-
this.wsjtxHeartbeat$.next(msg.wsjtx.payload);
|
|
113
|
-
return;
|
|
114
|
-
case 'StatusMessage':
|
|
115
|
-
this.wsjtxStatus$.next(msg.wsjtx.payload);
|
|
116
|
-
return;
|
|
117
|
-
case 'DecodeMessage':
|
|
118
|
-
this.wsjtxDecode$.next(msg.wsjtx.payload);
|
|
119
|
-
return;
|
|
120
|
-
case 'ClearMessage':
|
|
121
|
-
this.wsjtxClear$.next(msg.wsjtx.payload);
|
|
122
|
-
return;
|
|
123
|
-
case 'QsoLoggedMessage':
|
|
124
|
-
this.wsjtxQsoLogged$.next(msg.wsjtx.payload);
|
|
125
|
-
return;
|
|
126
|
-
case 'CloseMessage':
|
|
127
|
-
this.wsjtxClose$.next(msg.wsjtx.payload);
|
|
128
|
-
return;
|
|
129
|
-
case 'WSPRDecodeMessage':
|
|
130
|
-
this.wsjtxWsprDecode$.next(msg.wsjtx.payload);
|
|
131
|
-
return;
|
|
132
|
-
case 'LoggedAdifMessage':
|
|
133
|
-
this.wsjtxLoggedAdif$.next(msg.wsjtx.payload);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
65
|
+
if (!msg.wsjtx) {
|
|
66
|
+
return;
|
|
136
67
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
68
|
+
this.connected$.next(true);
|
|
69
|
+
this.wsjtxId = msg.wsjtx.payload.id;
|
|
70
|
+
switch (msg.wsjtx.type) {
|
|
71
|
+
case 'HeartbeatMessage':
|
|
72
|
+
this.heartbeat$.next(msg.wsjtx.payload);
|
|
73
|
+
return;
|
|
74
|
+
case 'StatusMessage':
|
|
75
|
+
this.status$.next(msg.wsjtx.payload);
|
|
76
|
+
return;
|
|
77
|
+
case 'DecodeMessage':
|
|
78
|
+
this.decode$.next(msg.wsjtx.payload);
|
|
79
|
+
return;
|
|
80
|
+
case 'ClearMessage':
|
|
81
|
+
this.clear$.next(msg.wsjtx.payload);
|
|
82
|
+
return;
|
|
83
|
+
case 'QsoLoggedMessage':
|
|
84
|
+
this.qsoLogged$.next(msg.wsjtx.payload);
|
|
85
|
+
return;
|
|
86
|
+
case 'CloseMessage':
|
|
87
|
+
this.close$.next(msg.wsjtx.payload);
|
|
88
|
+
return;
|
|
89
|
+
case 'WSPRDecodeMessage':
|
|
90
|
+
this.wsprDecode$.next(msg.wsjtx.payload);
|
|
91
|
+
return;
|
|
92
|
+
case 'LoggedAdifMessage':
|
|
93
|
+
this.loggedAdif$.next(msg.wsjtx.payload);
|
|
94
|
+
return;
|
|
144
95
|
}
|
|
145
96
|
}
|
|
146
|
-
/** Get the currently configured kel-agent host. */
|
|
147
|
-
getHost() {
|
|
148
|
-
return localStorage.getItem(this.localStorageHostKey) || this.defaultAgentHost;
|
|
149
|
-
}
|
|
150
|
-
/** Get the currently configured kel-agent port. */
|
|
151
|
-
getPort() {
|
|
152
|
-
let portStr = localStorage.getItem(this.localStoragePortKey);
|
|
153
|
-
if (portStr == null) {
|
|
154
|
-
return this.defaultAgentPort;
|
|
155
|
-
}
|
|
156
|
-
let portNum = parseInt(portStr, 10);
|
|
157
|
-
if (isNaN(portNum)) {
|
|
158
|
-
return this.defaultAgentPort;
|
|
159
|
-
}
|
|
160
|
-
return portNum;
|
|
161
|
-
}
|
|
162
|
-
/** Set the kel-agent host. */
|
|
163
|
-
setHost(host) {
|
|
164
|
-
localStorage.setItem(this.localStorageHostKey, host);
|
|
165
|
-
this.connect();
|
|
166
|
-
}
|
|
167
|
-
/** Set the kel-agent port. */
|
|
168
|
-
setPort(port) {
|
|
169
|
-
localStorage.setItem(this.localStoragePortKey, String(port));
|
|
170
|
-
this.connect();
|
|
171
|
-
}
|
|
172
97
|
/** Send a command to WSJT-X to clear the Band Activity window. */
|
|
173
|
-
|
|
174
|
-
var _a;
|
|
98
|
+
clearBandActivity() {
|
|
175
99
|
const wsMsg = {
|
|
176
100
|
wsjtx: {
|
|
177
101
|
type: 'ClearMessage',
|
|
178
102
|
payload: { id: this.wsjtxId, window: 0 },
|
|
179
103
|
},
|
|
180
104
|
};
|
|
181
|
-
|
|
105
|
+
this.messages.txMessage$.next(wsMsg);
|
|
182
106
|
}
|
|
183
107
|
/** Send a command to WSJT-X to clear the Rx Frequency window. */
|
|
184
|
-
|
|
185
|
-
var _a;
|
|
108
|
+
clearRxFreqWindow() {
|
|
186
109
|
const wsMsg = {
|
|
187
110
|
wsjtx: {
|
|
188
111
|
type: 'ClearMessage',
|
|
189
112
|
payload: { id: this.wsjtxId, window: 1 },
|
|
190
113
|
},
|
|
191
114
|
};
|
|
192
|
-
|
|
115
|
+
this.messages.txMessage$.next(wsMsg);
|
|
193
116
|
}
|
|
194
117
|
/** Send a command to WSJT-X to clear the Band Activity and Rx Frequency windows. */
|
|
195
|
-
|
|
196
|
-
var _a;
|
|
118
|
+
clearAll() {
|
|
197
119
|
const wsMsg = {
|
|
198
120
|
wsjtx: {
|
|
199
121
|
type: 'ClearMessage',
|
|
200
122
|
payload: { id: this.wsjtxId, window: 2 },
|
|
201
123
|
},
|
|
202
124
|
};
|
|
203
|
-
|
|
125
|
+
this.messages.txMessage$.next(wsMsg);
|
|
204
126
|
}
|
|
205
127
|
/** Send a command to WSJT-X to replay messages. Useful for a fresh client that wants to hear
|
|
206
128
|
* previous WSJT-X decodes. */
|
|
207
|
-
|
|
208
|
-
var _a;
|
|
129
|
+
replay() {
|
|
209
130
|
const wsMsg = {
|
|
210
131
|
wsjtx: {
|
|
211
132
|
type: 'ReplayMessage',
|
|
212
133
|
payload: { id: this.wsjtxId },
|
|
213
134
|
},
|
|
214
135
|
};
|
|
215
|
-
|
|
136
|
+
this.messages.txMessage$.next(wsMsg);
|
|
216
137
|
}
|
|
217
138
|
/** Send a command to WSJT-X to halt any transmissions immediately. */
|
|
218
|
-
|
|
219
|
-
var _a;
|
|
139
|
+
haltTxNow() {
|
|
220
140
|
const wsMsg = {
|
|
221
141
|
wsjtx: {
|
|
222
142
|
type: 'HaltTxMessage',
|
|
223
143
|
payload: { id: this.wsjtxId, autoTxOnly: false },
|
|
224
144
|
},
|
|
225
145
|
};
|
|
226
|
-
|
|
146
|
+
this.messages.txMessage$.next(wsMsg);
|
|
227
147
|
}
|
|
228
148
|
/** Send a command to WSJT-X to stop auto-transmitting after finishing the current round. */
|
|
229
|
-
|
|
230
|
-
var _a;
|
|
149
|
+
haltTxAfterCurrent() {
|
|
231
150
|
const wsMsg = {
|
|
232
151
|
wsjtx: {
|
|
233
152
|
type: 'HaltTxMessage',
|
|
234
153
|
payload: { id: this.wsjtxId, autoTxOnly: true },
|
|
235
154
|
},
|
|
236
155
|
};
|
|
237
|
-
|
|
156
|
+
this.messages.txMessage$.next(wsMsg);
|
|
238
157
|
}
|
|
239
158
|
/** Send a command to WSJT-X to reply to the given decode. The message must include CQ or QRZ. */
|
|
240
|
-
|
|
241
|
-
var _a;
|
|
159
|
+
reply(decode) {
|
|
242
160
|
const wsMsg = {
|
|
243
161
|
wsjtx: {
|
|
244
162
|
type: 'ReplyMessage',
|
|
@@ -254,7 +172,69 @@ class AgentService {
|
|
|
254
172
|
},
|
|
255
173
|
},
|
|
256
174
|
};
|
|
257
|
-
|
|
175
|
+
this.messages.txMessage$.next(wsMsg);
|
|
176
|
+
}
|
|
177
|
+
/** Send a command to WSJT-X to reply to the given decode. The message must include CQ or QRZ. */
|
|
178
|
+
highlightCallsign(highlightMsg) {
|
|
179
|
+
highlightMsg.id = this.wsjtxId;
|
|
180
|
+
const wsMsg = {
|
|
181
|
+
wsjtx: {
|
|
182
|
+
type: 'HighlightCallsignMessage',
|
|
183
|
+
payload: highlightMsg,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
this.messages.txMessage$.next(wsMsg);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Send a command to WSJT-X to transmit the given free text. If the text is too long to be
|
|
190
|
+
* encoded in a single message, it may be silently truncated. */
|
|
191
|
+
sendFreeText(freeText) {
|
|
192
|
+
freeText.id = this.wsjtxId;
|
|
193
|
+
const wsMsg = {
|
|
194
|
+
wsjtx: {
|
|
195
|
+
type: 'FreeTextMessage',
|
|
196
|
+
payload: freeText,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
this.messages.txMessage$.next(wsMsg);
|
|
200
|
+
}
|
|
201
|
+
/** Send a command to WSJT-X to set the local station's Maidenhead grid. This is temporary,
|
|
202
|
+
* lasting only as long as WSJT-X is running. */
|
|
203
|
+
setLocation(grid) {
|
|
204
|
+
const wsMsg = {
|
|
205
|
+
wsjtx: {
|
|
206
|
+
type: 'LocationMessage',
|
|
207
|
+
payload: {
|
|
208
|
+
id: this.wsjtxId,
|
|
209
|
+
location: grid,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
this.messages.txMessage$.next(wsMsg);
|
|
214
|
+
}
|
|
215
|
+
/** Send a command to WSJT-X to switch to the named configuration. */
|
|
216
|
+
switchConfiguration(configName) {
|
|
217
|
+
const wsMsg = {
|
|
218
|
+
wsjtx: {
|
|
219
|
+
type: 'SwitchConfigurationMessage',
|
|
220
|
+
payload: {
|
|
221
|
+
id: this.wsjtxId,
|
|
222
|
+
configurationName: configName,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
this.messages.txMessage$.next(wsMsg);
|
|
227
|
+
}
|
|
228
|
+
/** Send a command to WSJT-X to set the given configuration parameters. */
|
|
229
|
+
configure(config) {
|
|
230
|
+
config.id = this.wsjtxId;
|
|
231
|
+
const wsMsg = {
|
|
232
|
+
wsjtx: {
|
|
233
|
+
type: 'ConfigureMessage',
|
|
234
|
+
payload: config,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
this.messages.txMessage$.next(wsMsg);
|
|
258
238
|
}
|
|
259
239
|
/** Given a decode message, format a string the same way as displayed in the WSJT-X Band
|
|
260
240
|
* Activity/Rx Frequency windows. */
|
|
@@ -272,22 +252,238 @@ class AgentService {
|
|
|
272
252
|
.padStart(4)} ${msg.deltaFrequency.toString().padStart(4)} ~ ${msg.message}`;
|
|
273
253
|
}
|
|
274
254
|
}
|
|
275
|
-
|
|
255
|
+
WsjtxService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: WsjtxService, deps: [{ token: AgentMessageService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
256
|
+
WsjtxService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: WsjtxService, providedIn: 'root' });
|
|
257
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: WsjtxService, decorators: [{
|
|
258
|
+
type: Injectable,
|
|
259
|
+
args: [{
|
|
260
|
+
providedIn: 'root',
|
|
261
|
+
}]
|
|
262
|
+
}], ctorParameters: function () { return [{ type: AgentMessageService }]; } });
|
|
263
|
+
|
|
264
|
+
class HamlibService {
|
|
265
|
+
constructor(messages) {
|
|
266
|
+
this.messages = messages;
|
|
267
|
+
/** Whether we're getting any messages from Hamlib. */
|
|
268
|
+
this.connected$ = new BehaviorSubject(false);
|
|
269
|
+
/** Subject for listening to Hamlib "RigState" messages. */
|
|
270
|
+
this.rigState$ = new BehaviorSubject(null);
|
|
271
|
+
this.setupBehaviors();
|
|
272
|
+
}
|
|
273
|
+
setupBehaviors() {
|
|
274
|
+
this.messages.rxMessage$.subscribe((msg) => this.handleMessage(msg));
|
|
275
|
+
// if we haven't heard from Hamlib in 15 seconds, consider it down
|
|
276
|
+
this.connected$.pipe(debounceTime(15000)).subscribe(() => {
|
|
277
|
+
this.connected$.next(false);
|
|
278
|
+
});
|
|
279
|
+
// When Hamlib goes down, clear its persistent message subjects
|
|
280
|
+
this.connected$.subscribe((isUp) => {
|
|
281
|
+
if (!isUp) {
|
|
282
|
+
this.rigState$.next(null);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
handleMessage(msg) {
|
|
287
|
+
if (!msg.hamlib) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
this.connected$.next(true);
|
|
291
|
+
switch (msg.hamlib.type) {
|
|
292
|
+
case 'RigState':
|
|
293
|
+
this.rigState$.next(msg.hamlib.payload);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
HamlibService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: HamlibService, deps: [{ token: AgentMessageService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
299
|
+
HamlibService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: HamlibService, providedIn: 'root' });
|
|
300
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: HamlibService, decorators: [{
|
|
301
|
+
type: Injectable,
|
|
302
|
+
args: [{
|
|
303
|
+
providedIn: 'root',
|
|
304
|
+
}]
|
|
305
|
+
}], ctorParameters: function () { return [{ type: AgentMessageService }]; } });
|
|
306
|
+
|
|
307
|
+
class AgentService {
|
|
308
|
+
constructor(messages, hamlibService, wsjtxService) {
|
|
309
|
+
this.messages = messages;
|
|
310
|
+
this.hamlibService = hamlibService;
|
|
311
|
+
this.wsjtxService = wsjtxService;
|
|
312
|
+
/** Whether we're connected to the agent. */
|
|
313
|
+
this.connectedState$ = new BehaviorSubject(false);
|
|
314
|
+
this.defaultAgentHost = 'localhost';
|
|
315
|
+
this.defaultAgentPort = 8081;
|
|
316
|
+
this.localStorageHostKey = 'agent-host';
|
|
317
|
+
this.localStoragePortKey = 'agent-port';
|
|
318
|
+
this.agentHost = this.defaultAgentHost;
|
|
319
|
+
this.agentPort = this.defaultAgentPort;
|
|
320
|
+
this.agentWebSocketSubject = null;
|
|
321
|
+
this.agentWebsocketSubscription = null;
|
|
322
|
+
this.hamlibState$ = this.hamlibService.connected$;
|
|
323
|
+
this.hamlibRigState$ = this.hamlibService.rigState$;
|
|
324
|
+
this.wsjtxState$ = this.wsjtxService.connected$;
|
|
325
|
+
this.wsjtxHeartbeat$ = this.wsjtxService.heartbeat$;
|
|
326
|
+
this.wsjtxStatus$ = this.wsjtxService.status$;
|
|
327
|
+
this.wsjtxDecode$ = this.wsjtxService.decode$;
|
|
328
|
+
this.wsjtxClear$ = this.wsjtxService.clear$;
|
|
329
|
+
this.wsjtxQsoLogged$ = this.wsjtxService.qsoLogged$;
|
|
330
|
+
this.wsjtxClose$ = this.wsjtxService.close$;
|
|
331
|
+
this.wsjtxWsprDecode$ = this.wsjtxService.wsprDecode$;
|
|
332
|
+
this.wsjtxLoggedAdif$ = this.wsjtxService.loggedAdif$;
|
|
333
|
+
}
|
|
334
|
+
init() {
|
|
335
|
+
this.messages.txMessage$.subscribe((msg) => this.send(msg));
|
|
336
|
+
this.agentHost = this.getHost();
|
|
337
|
+
this.agentPort = this.getPort();
|
|
338
|
+
this.connect();
|
|
339
|
+
}
|
|
340
|
+
/** Connect (or reconnect) the websocket to the kel-agent server. */
|
|
341
|
+
connect() {
|
|
342
|
+
if (this.agentWebsocketSubscription) {
|
|
343
|
+
this.agentWebsocketSubscription.unsubscribe();
|
|
344
|
+
}
|
|
345
|
+
this.agentHost = this.getHost();
|
|
346
|
+
this.agentPort = this.getPort();
|
|
347
|
+
const protocol = this.agentHost === 'localhost' ? 'ws://' : 'wss://';
|
|
348
|
+
this.agentWebSocketSubject = webSocket({
|
|
349
|
+
url: protocol + this.agentHost + ':' + this.agentPort + '/websocket',
|
|
350
|
+
});
|
|
351
|
+
this.connectedState$.next(true);
|
|
352
|
+
this.agentWebsocketSubscription = this.agentWebSocketSubject
|
|
353
|
+
.pipe(retryWhen((errors) =>
|
|
354
|
+
// retry the websocket connection after 10 seconds
|
|
355
|
+
errors.pipe(tap(() => this.connectedState$.next(false)), delay(10000))))
|
|
356
|
+
.subscribe({
|
|
357
|
+
next: (msg) => {
|
|
358
|
+
this.connectedState$.next(true);
|
|
359
|
+
this.messages.rxMessage$.next(msg);
|
|
360
|
+
},
|
|
361
|
+
error: () => this.connectedState$.next(false),
|
|
362
|
+
complete: () => this.connectedState$.next(false),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
/** Get the currently configured kel-agent host. */
|
|
366
|
+
getHost() {
|
|
367
|
+
return (localStorage.getItem(this.localStorageHostKey) || this.defaultAgentHost);
|
|
368
|
+
}
|
|
369
|
+
/** Get the currently configured kel-agent port. */
|
|
370
|
+
getPort() {
|
|
371
|
+
let portStr = localStorage.getItem(this.localStoragePortKey);
|
|
372
|
+
if (portStr == null) {
|
|
373
|
+
return this.defaultAgentPort;
|
|
374
|
+
}
|
|
375
|
+
let portNum = parseInt(portStr, 10);
|
|
376
|
+
if (isNaN(portNum)) {
|
|
377
|
+
return this.defaultAgentPort;
|
|
378
|
+
}
|
|
379
|
+
return portNum;
|
|
380
|
+
}
|
|
381
|
+
/** Set the kel-agent host. */
|
|
382
|
+
setHost(host) {
|
|
383
|
+
localStorage.setItem(this.localStorageHostKey, host);
|
|
384
|
+
this.connect();
|
|
385
|
+
}
|
|
386
|
+
/** Set the kel-agent port. */
|
|
387
|
+
setPort(port) {
|
|
388
|
+
localStorage.setItem(this.localStoragePortKey, String(port));
|
|
389
|
+
this.connect();
|
|
390
|
+
}
|
|
391
|
+
send(wsMsg) {
|
|
392
|
+
var _a;
|
|
393
|
+
(_a = this.agentWebSocketSubject) === null || _a === void 0 ? void 0 : _a.next(wsMsg);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Send a command to WSJT-X to clear the Band Activity window.
|
|
397
|
+
*
|
|
398
|
+
* @deprecated Use {@link WsjtxService.clearBandActivity} instead.
|
|
399
|
+
*/
|
|
400
|
+
sendWsjtxClearBandActivity() {
|
|
401
|
+
this.wsjtxService.clearBandActivity();
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Send a command to WSJT-X to clear the Rx Frequency window.
|
|
405
|
+
*
|
|
406
|
+
* @deprecated Use {@link WsjtxService.clearRxFreqWindow} instead.
|
|
407
|
+
*/
|
|
408
|
+
sendWsjtxClearRxFreqWindow() {
|
|
409
|
+
this.wsjtxService.clearRxFreqWindow();
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Send a command to WSJT-X to clear the Band Activity and Rx Frequency windows.
|
|
413
|
+
*
|
|
414
|
+
* @deprecated Use {@link WsjtxService.clearAll} instead.
|
|
415
|
+
*/
|
|
416
|
+
sendWsjtxClearAll() {
|
|
417
|
+
this.wsjtxService.clearAll();
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Send a command to WSJT-X to replay messages. Useful for a fresh client that wants to hear
|
|
421
|
+
* previous WSJT-X decodes.
|
|
422
|
+
*
|
|
423
|
+
* @deprecated Use {@link WsjtxService.replay} instead.
|
|
424
|
+
*/
|
|
425
|
+
sendWsjtxReplay() {
|
|
426
|
+
this.wsjtxService.replay();
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Send a command to WSJT-X to halt any transmissions immediately.
|
|
430
|
+
*
|
|
431
|
+
* @deprecated Use {@link WsjtxService.haltTxNow} instead.
|
|
432
|
+
*/
|
|
433
|
+
sendWsjtxHaltTxNow() {
|
|
434
|
+
this.wsjtxService.haltTxNow();
|
|
435
|
+
}
|
|
436
|
+
/** Send a command to WSJT-X to stop auto-transmitting after finishing the current round.
|
|
437
|
+
*
|
|
438
|
+
* @deprecated Use {@link WsjtxService.haltTxAfterCurrent} instead.
|
|
439
|
+
*/
|
|
440
|
+
sendWsjtxHaltTxAfterCurrent() {
|
|
441
|
+
this.wsjtxService.haltTxAfterCurrent();
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Send a command to WSJT-X to reply to the given decode. The message must include CQ or QRZ.
|
|
445
|
+
*
|
|
446
|
+
* @deprecated Use {@link WsjtxService.reply} instead.
|
|
447
|
+
*/
|
|
448
|
+
sendWsjtxReply(decode) {
|
|
449
|
+
this.wsjtxService.reply(decode);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Send a command to WSJT-X to reply to the given decode. The message must include CQ or QRZ.
|
|
453
|
+
*
|
|
454
|
+
* @deprecated Use {@link WsjtxService.highlightCallsign} instead.
|
|
455
|
+
*/
|
|
456
|
+
sendWsjtxHighlightCallsign(highlightMsg) {
|
|
457
|
+
this.wsjtxService.highlightCallsign(highlightMsg);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Given a decode message, format a string the same way as displayed in the WSJT-X Band
|
|
461
|
+
* Activity/Rx Frequency windows.
|
|
462
|
+
*
|
|
463
|
+
* @deprecated Use {@link WsjtxService.formatDecode} instead.
|
|
464
|
+
*/
|
|
465
|
+
static formatDecode(msg) {
|
|
466
|
+
return WsjtxService.formatDecode(msg);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
AgentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentService, deps: [{ token: AgentMessageService }, { token: HamlibService }, { token: WsjtxService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
276
470
|
AgentService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentService, providedIn: 'root' });
|
|
277
471
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: AgentService, decorators: [{
|
|
278
472
|
type: Injectable,
|
|
279
473
|
args: [{
|
|
280
|
-
providedIn: 'root'
|
|
474
|
+
providedIn: 'root',
|
|
281
475
|
}]
|
|
282
|
-
}], ctorParameters: function () { return []; } });
|
|
476
|
+
}], ctorParameters: function () { return [{ type: AgentMessageService }, { type: HamlibService }, { type: WsjtxService }]; } });
|
|
283
477
|
|
|
284
478
|
/*
|
|
285
479
|
* Public API Surface of ngx-kel-agent
|
|
286
480
|
*/
|
|
481
|
+
// export * from './lib/ngx-kel-agent.component';
|
|
482
|
+
// export * from './lib/ngx-kel-agent.module';
|
|
287
483
|
|
|
288
484
|
/**
|
|
289
485
|
* Generated bundle index. Do not edit.
|
|
290
486
|
*/
|
|
291
487
|
|
|
292
|
-
export { AgentService };
|
|
488
|
+
export { AgentMessageService, AgentService, HamlibService, WsjtxService };
|
|
293
489
|
//# sourceMappingURL=ngx-kel-agent.mjs.map
|