When running bonob outside of sonos network ability to register with sonos using remote bonob

This commit is contained in:
simojenki
2021-08-06 18:12:55 +10:00
parent 22b8bf76d2
commit 27dc933ee0
8 changed files with 95 additions and 40 deletions

View File

@@ -54,15 +54,17 @@ Bonob will now auto-register itself with sonos on startup, updating the registra
### Running bonob on a different network to your sonos devices ### Running bonob on a different network to your sonos devices
Running bonob outside of your lan will require registering your bonob install with your sonos devices from within your lan. Running bonob outside of your lan will require registering your bonob install with your sonos devices from within your LAN.
If you are running this on the internet, you should put bonob behind a reverse proxy and use certificates/https. If you are using bonob over the Internet, you do this at your own risk and should use TLS.
Start bonob outside the lan with sonos discovery & registration disabled as they are meaningless in this case, ie. Start bonob outside the LAN with sonos discovery & registration disabled as they are meaningless in this case, ie.
```bash ```bash
docker run \ docker run \
-e BONOB_PORT=4534 \ -e BONOB_PORT=4534 \
-e BONOB_SONOS_SERVICE_NAME=MyAwesomeMusic \
-e BONOB_SECRET=changeme \
-e BONOB_URL=https://my-server.example.com/bonob \ -e BONOB_URL=https://my-server.example.com/bonob \
-e BONOB_SONOS_AUTO_REGISTER=false \ -e BONOB_SONOS_AUTO_REGISTER=false \
-e BONOB_SONOS_DEVICE_DISCOVERY=false \ -e BONOB_SONOS_DEVICE_DISCOVERY=false \
@@ -71,17 +73,16 @@ docker run \
simojenki/bonob simojenki/bonob
``` ```
Now inside the lan that contains the sonos devices run bonob registration, using the same BONOB_URL as above, and with discovery enabled. Make sure to use host networking so that bonob can find the sonos devices (or provide a BONOB_SONOS_SEED_HOST) Now within the LAN that contains the sonos devices run bonob the registration process.
```bash ```bash
docker run \ docker run \
-e BONOB_URL=https://my-server.example.com/bonob \
-e BONOB_SONOS_DEVICE_DISCOVERY=true \
--network host \ --network host \
simojenki/bonob register simojenki/bonob register https://my-server.example.com/bonob
``` ```
### Running bonob and navidrome using docker-compose ### Running bonob and navidrome using docker-compose
```yaml ```yaml
version: "3" version: "3"
services: services:

View File

@@ -46,9 +46,10 @@
"xpath-ts": "^1.3.13" "xpath-ts": "^1.3.13"
}, },
"scripts": { "scripts": {
"clean": "rm -Rf build",
"build": "tsc", "build": "tsc",
"dev": "BONOB_PORT=4000 nodemon ./src/app.ts", "dev": "BONOB_PORT=4000 BONOB_URL=http://$(hostname):4000 BONOB_SONOS_SERVICE_NAME=bonobDev BONOB_SONOS_DEVICE_DISCOVERY=false BONOB_SONOS_AUTO_REGISTER=false nodemon ./src/app.ts",
"test": "jest", "register-dev": "ts-node ./src/register.ts http://$(hostname):4000",
"client-test": "ts-node tests/bonob_client.ts" "test": "jest"
} }
} }

View File

@@ -67,6 +67,10 @@ const app = server(
true, true,
); );
app.listen(config.port, () => {
logger.info(`Listening on ${config.port} available @ ${config.bonobUrl}`);
});
if (config.sonos.autoRegister) { if (config.sonos.autoRegister) {
sonosSystem.register(bonob).then((success) => { sonosSystem.register(bonob).then((success) => {
if (success) { if (success) {
@@ -75,10 +79,12 @@ if (config.sonos.autoRegister) {
); );
} }
}); });
} else if(config.sonos.deviceDiscovery) {
sonosSystem.devices().then(devices => {
devices.forEach(d => {
logger.info(`Found device ${d.name}(${d.group}) @ ${d.ip}:${d.port}`)
})
})
} }
app.listen(config.port, () => {
logger.info(`Listening on ${config.port} available @ ${config.bonobUrl}`);
});
export default app; export default app;

View File

@@ -1,26 +1,15 @@
import readConfig from "./config"; import registrar from "./registrar";
import logger from "./logger"; import { URLBuilder } from "./url_builder";
import sonos, { bonobService } from "./sonos";
const config = readConfig(); const params = process.argv.slice(2);
const bonob = bonobService( if (params.length != 1) {
config.sonos.serviceName, console.error("Usage: register [URL to bonob]");
config.sonos.sid,
config.bonobUrl,
"AppLink"
);
const sonosSystem = sonos(config.sonos.deviceDiscovery, config.sonos.seedHost);
sonosSystem.register(bonob).then((success) => {
if (success) {
logger.info(
`Successfully registered ${bonob.name}(SID:${bonob.sid}) with sonos`
);
process.exit(0);
} else {
logger.error(`Failed to register ${bonob.name}(SID:${bonob.sid}) with sonos!!`)
process.exit(1); process.exit(1);
} }
const bonobUrl = new URLBuilder(params[0]!);
registrar(bonobUrl)().then((success) => {
if (success) console.log(`Successfully registered bonob @ ${bonobUrl} with sonos`);
else console.error(`Failed registering bonob @ ${bonobUrl} with sonos`);
}); });

19
src/registrar.ts Normal file
View File

@@ -0,0 +1,19 @@
import axios from "axios";
import logger from "./logger";
import sonos, { bonobService } from "./sonos";
import { URLBuilder } from "./url_builder";
export default (bonobUrl: URLBuilder) => async () => {
const about = bonobUrl.append({ pathname: "/about" });
logger.info(`Fetching bonob service about from ${about}`);
return axios
.get(about.href())
.then((res) => {
if (res.status == 200) return res.data;
else throw `Unexpected response status ${res.status} from ${about}`;
})
.then((about) =>
bonobService(about.service.name, about.service.sid, bonobUrl)
)
.then((bonobService) => sonos(true).register(bonobService));
};

View File

@@ -101,6 +101,15 @@ function server(
); );
}); });
app.get("/about", (_, res) => {
return res.send({
service: {
name: service.name,
sid: service.sid
}
});
});
app.post(REGISTER_ROUTE, (_, res) => { app.post(REGISTER_ROUTE, (_, res) => {
sonos.register(service).then((success) => { sonos.register(service).then((success) => {
if (success) { if (success) {

View File

@@ -132,7 +132,7 @@ const setupDiscovery = (
sonosSeedHost?: string sonosSeedHost?: string
): Promise<boolean> => { ): Promise<boolean> => {
if (sonosSeedHost == undefined || sonosSeedHost == "") { if (sonosSeedHost == undefined || sonosSeedHost == "") {
logger.info("Trying to auto discover sonos devices"); logger.info("Trying to discover sonos devices");
return manager.InitializeWithDiscovery(10); return manager.InitializeWithDiscovery(10);
} else { } else {
logger.info(`Trying to discover sonos devices using seed ${sonosSeedHost}`); logger.info(`Trying to discover sonos devices using seed ${sonosSeedHost}`);

View File

@@ -307,6 +307,36 @@ describe("server", () => {
}); });
}); });
describe("/about", () => {
const sonos = {
register: jest.fn(),
};
const theService = aService({
name: "We can all live a life of service",
sid: 999,
});
const server = makeServer(
sonos as unknown as Sonos,
theService,
bonobUrl,
new InMemoryMusicService()
);
it("should report some information about the service", async () => {
const res = await request(server)
.get(bonobUrl.append({ pathname: "/about" }).path())
.send();
expect(res.status).toEqual(200);
expect(res.body).toEqual({
service: {
name: theService.name,
sid: theService.sid
}
});
});
});
describe("/register", () => { describe("/register", () => {
const sonos = { const sonos = {
register: jest.fn(), register: jest.fn(),
@@ -322,7 +352,7 @@ describe("server", () => {
new InMemoryMusicService() new InMemoryMusicService()
); );
describe("when is succesfull", () => { describe("when is successful", () => {
it("should return a nice message", async () => { it("should return a nice message", async () => {
sonos.register.mockResolvedValue(true); sonos.register.mockResolvedValue(true);
@@ -338,7 +368,7 @@ describe("server", () => {
}); });
}); });
describe("when is unsuccesfull", () => { describe("when is unsuccessful", () => {
it("should return a failure message", async () => { it("should return a failure message", async () => {
sonos.register.mockResolvedValue(false); sonos.register.mockResolvedValue(false);