-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4ec3099
commit 3f8a500
Showing
5 changed files
with
263 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
packages/server/src/server/services/remoteConfigService/commands.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { isEmpty } from "@server/helpers/utils"; | ||
import { Server } from "@server"; | ||
|
||
|
||
// This whole file was bascially cribbed from main.ts. I imagine the code should | ||
// be consolidated and extracted somwhere. | ||
|
||
|
||
function quickStrConvert (val: string) { | ||
if (val.toLowerCase() === "true") return true; | ||
if (val.toLowerCase() === "false") return false; | ||
return val; | ||
} | ||
|
||
async function handleSet (parts: string[]) { | ||
const configKey = parts.length > 1 ? parts[1] : null; | ||
const configValue = parts.length > 2 ? parts[2] : null; | ||
if (!configKey || !configValue) { | ||
return "Empty config key/value. Ignoring..."; | ||
} | ||
|
||
if (!Server().repo.hasConfig(configKey)) { | ||
return `Configuration, '${configKey}' does not exist. Ignoring...`; | ||
} | ||
|
||
try { | ||
await Server().repo.setConfig(configKey, quickStrConvert(configValue)); | ||
return `Successfully set config item, '${configKey}' to, '${quickStrConvert(configValue)}'`; | ||
} catch (ex: any) { | ||
Server().log(`Failed set config item, '${configKey}'\n${ex}`, "error"); | ||
return `Failed set config item, '${configKey}'\n${ex}`; | ||
} | ||
} | ||
|
||
async function handleShow (parts: string[]) { | ||
const configKey = parts.length > 1 ? parts[1] : null; | ||
if (!configKey) { | ||
return "Empty config key. Ignoring..."; | ||
} | ||
|
||
if (!Server().repo.hasConfig(configKey)) { | ||
return `Configuration, '${configKey}' does not exist. Ignoring...`; | ||
} | ||
|
||
try { | ||
const value = await Server().repo.getConfig(configKey); | ||
return `${configKey} -> ${value}`; | ||
} catch (ex: any) { | ||
Server().log(`Failed set config item, '${configKey}'\n${ex}`, "error"); | ||
return `Failed set config item, '${configKey}'\n${ex}`; | ||
} | ||
} | ||
|
||
const help = `[================================== Help Menu ==================================]\n | ||
Available Commands: | ||
- help: Show the help menu | ||
- restart: Relaunch/Restart the app | ||
- set: Set configuration item -> \`set <config item> <value>\` | ||
Available configuration items: | ||
-> tutorial_is_done: boolean | ||
-> socket_port: number | ||
-> server_address: string | ||
-> ngrok_key: string | ||
-> password: string | ||
-> auto_caffeinate: boolean | ||
-> auto_start: boolean | ||
-> enable_ngrok: boolean | ||
-> encrypt_coms: boolean | ||
-> hide_dock_icon: boolean | ||
-> last_fcm_restart: number | ||
-> start_via_terminal: boolean | ||
- show: Show the current configuration for an item -> \`show <config item>\` | ||
- exit: Exit the configurator | ||
\n[===============================================================================]`; | ||
|
||
|
||
export async function handleLine (line: string) : Promise<[string, boolean]> { | ||
line = line.trim(); | ||
if (line === "") return ['', true]; | ||
|
||
// Handle the standard input | ||
const parts = line.split(" "); | ||
if (isEmpty(parts)) return ['', true]; | ||
|
||
if (!Server()) { | ||
return ["Server is not running???????", true]; | ||
} | ||
|
||
switch (parts[0].toLowerCase()) { | ||
case "help": | ||
return [help, true]; | ||
case "set": | ||
return [await handleSet(parts), true]; | ||
break; | ||
case "show": | ||
return [await handleShow(parts), true]; | ||
break; | ||
case "restart": | ||
case "relaunch": | ||
Server().relaunch(); | ||
return ["Okay, restarting", true]; | ||
case "exit": | ||
return ["Thank you for using the Bluebubbles configurator!", false]; | ||
default: | ||
return ["Unrecognized command. Type 'help' for help.", true]; | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
packages/server/src/server/services/remoteConfigService/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import * as net from "net"; | ||
import { Server } from "@server"; | ||
import { LogLevel } from "electron-log"; | ||
import { LineExtractor } from "./lineExtractor"; | ||
import { app } from "electron"; | ||
import { handleLine } from "./commands"; | ||
|
||
|
||
const PROMPT = 'bluebubbles-configurator>'; | ||
|
||
|
||
export class RemoteConfigService { | ||
server: net.Server; | ||
|
||
clients: Set<net.Socket> = new Set(); | ||
|
||
socketPath: string; | ||
|
||
constructor () { | ||
// not sure if this socketPath stuff belongs in fileSystem/index.ts | ||
const isDev = process.env.NODE_ENV !== "production"; | ||
this.socketPath = app.getPath("userData"); | ||
if (isDev) { | ||
this.socketPath = path.join(this.socketPath, "bluebubbles-server"); | ||
} | ||
this.socketPath = path.join(this.socketPath, "remote-config.sock"); | ||
|
||
this.log(`Remote Config Service socket path: ${this.socketPath}`, "debug"); | ||
} | ||
|
||
private log(message: string, level: LogLevel = "info") { | ||
Server().log(`[RemoteConfigService] ${String(message)}`, level); | ||
} | ||
|
||
start() { | ||
this.server = net.createServer({allowHalfOpen: false}, (client: net.Socket) => { | ||
this.handleClient(client); | ||
}); | ||
|
||
if (fs.existsSync(this.socketPath)) { | ||
fs.unlinkSync(this.socketPath); | ||
} | ||
this.server.listen(this.socketPath); | ||
|
||
this.server.on("error", err => { | ||
this.log("An error occured in the RemoteConfigService server socket", "error"); | ||
this.log(err.toString(), "error"); | ||
this.closeServer(); | ||
}); | ||
} | ||
|
||
private handleClient(client: net.Socket) { | ||
this.log("Remote Config Service client connected", "debug"); | ||
|
||
this.clients.add(client); | ||
const lineExtractor = new LineExtractor(); | ||
|
||
client.write(`Welcome to the BlueBubbles configurator!\nType 'help' for help.\nType 'exit' to exit.\n${PROMPT} `); | ||
|
||
client.on("data", async (data: Buffer) => { | ||
for (const line of lineExtractor.feed(data)) { | ||
await this.handleLine(client, line); | ||
} | ||
}); | ||
client.on("close", () => { | ||
this.log("Remote Config Service client closed", "debug"); | ||
this.clients.delete(client); | ||
}); | ||
client.on("error", err => { | ||
this.log("An error occured in a RemoteConfigService client", "error"); | ||
this.log(err.toString(), "error"); | ||
}); | ||
} | ||
|
||
private async handleLine (client: net.Socket, line: string) { | ||
this.log(`Remote Config Service client received line: ${JSON.stringify(line)}`, "debug"); | ||
const [response, keepOpen] = await handleLine(line); | ||
if (response) { | ||
client.write(`${response}\n`); | ||
} | ||
if (keepOpen) { | ||
client.write(`${PROMPT} `); | ||
} | ||
else { | ||
client.destroy(); | ||
} | ||
} | ||
|
||
private closeServer () { | ||
if (this.server === null) { | ||
return; | ||
} | ||
this.server.close(); | ||
this.server = null; | ||
} | ||
|
||
private destroyAllClients () { | ||
for (const client of this.clients) { | ||
client.destroy(); | ||
} | ||
this.clients = new Set(); | ||
} | ||
|
||
stop() { | ||
this.log("Stopping Remote Config Service..."); | ||
|
||
this.destroyAllClients(); | ||
this.closeServer(); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
packages/server/src/server/services/remoteConfigService/lineExtractor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export class LineExtractor { | ||
|
||
buffer: Buffer; | ||
|
||
constructor () { | ||
this.buffer = Buffer.from([]); | ||
} | ||
|
||
*feed (data: Buffer) { | ||
this.buffer = Buffer.concat([this.buffer, data]); | ||
while (true) { | ||
const i = this.buffer.indexOf(10); | ||
if (i === -1) break; | ||
|
||
yield this.buffer.subarray(0, i).toString('utf-8'); | ||
this.buffer = this.buffer.subarray(i + 1); | ||
} | ||
} | ||
} |