diff --git a/examples/boilerplate-react-buildless/index.html b/examples/boilerplate-react-buildless/index.html
index 88bb7d83..6e6a62b4 100644
--- a/examples/boilerplate-react-buildless/index.html
+++ b/examples/boilerplate-react-buildless/index.html
@@ -28,7 +28,7 @@
import { createRoot } from 'https://esm.sh/react-dom@18/client?dev';
import * as zebar from 'https://esm.sh/zebar@2';
- const providers = await zebar.createProviderGroup({
+ const providers = zebar.createProviderGroup({
cpu: { type: 'cpu' },
battery: { type: 'battery' },
memory: { type: 'memory' },
@@ -46,11 +46,13 @@
return (
-
CPU usage: {output.cpu.usage}
+
CPU usage: {output.cpu?.usage}
Battery charge: {output.battery?.chargePercent}
-
Memory usage: {output.memory.usage}
+
+ Memory usage: {output.memory?.usage}
+
Weather temp: {output.weather?.celsiusTemp}
diff --git a/examples/boilerplate-solid-ts/src/index.tsx b/examples/boilerplate-solid-ts/src/index.tsx
index 097a3786..f86d90b5 100644
--- a/examples/boilerplate-solid-ts/src/index.tsx
+++ b/examples/boilerplate-solid-ts/src/index.tsx
@@ -4,12 +4,11 @@ import { render } from 'solid-js/web';
import { createStore } from 'solid-js/store';
import * as zebar from 'zebar';
-const providers = await zebar.createProviderGroup({
+const providers = zebar.createProviderGroup({
cpu: { type: 'cpu' },
battery: { type: 'battery' },
memory: { type: 'memory' },
weather: { type: 'weather' },
- keyboard: { type: 'keyboard' },
});
render(() =>
, document.getElementById('root')!);
@@ -21,12 +20,11 @@ function App() {
return (
-
Keyboard: {output.keyboard.layout}
-
CPU usage: {output.cpu.usage}
+
CPU usage: {output.cpu?.usage}
Battery charge: {output.battery?.chargePercent}
-
Memory usage: {output.memory.usage}
+
Memory usage: {output.memory?.usage}
Weather temp: {output.weather?.celsiusTemp}
);
diff --git a/examples/starter/vanilla.html b/examples/starter/vanilla.html
index 1c731f10..6fc2cf8c 100644
--- a/examples/starter/vanilla.html
+++ b/examples/starter/vanilla.html
@@ -28,7 +28,7 @@
import { createRoot } from 'https://esm.sh/react-dom@18/client?dev';
import * as zebar from 'https://esm.sh/zebar@2';
- const providers = await zebar.createProviderGroup({
+ const providers = zebar.createProviderGroup({
network: { type: 'network' },
cpu: { type: 'cpu' },
date: { type: 'date', formatting: 'EEE d MMM t' },
@@ -47,23 +47,23 @@
}, []);
// Get icon to show for current network status.
- function getNetworkIcon() {
- switch (output.network.defaultInterface?.type) {
+ function getNetworkIcon(networkOutput) {
+ switch (networkOutput.defaultInterface?.type) {
case 'ethernet':
return
;
case 'wifi':
- if (output.network.defaultGateway?.signalStrength >= 80) {
+ if (networkOutput.defaultGateway?.signalStrength >= 80) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 65
+ networkOutput.defaultGateway?.signalStrength >= 65
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 40
+ networkOutput.defaultGateway?.signalStrength >= 40
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 25
+ networkOutput.defaultGateway?.signalStrength >= 25
) {
return
;
} else {
@@ -77,21 +77,21 @@
}
// Get icon to show for how much of the battery is charged.
- function getBatteryIcon() {
- if (output.battery.chargePercent > 90)
+ function getBatteryIcon(batteryOutput) {
+ if (batteryOutput.chargePercent > 90)
return
;
- if (output.battery.chargePercent > 70)
+ if (batteryOutput.chargePercent > 70)
return
;
- if (output.battery.chargePercent > 40)
+ if (batteryOutput.chargePercent > 40)
return
;
- if (output.battery.chargePercent > 20)
+ if (batteryOutput.chargePercent > 20)
return
;
return
;
}
// Get icon to show for current weather status.
- function getWeatherIcon() {
- switch (output.weather.status) {
+ function getWeatherIcon(weatherOutput) {
+ switch (weatherOutput.status) {
case 'clear_day':
return
;
case 'clear_night':
@@ -125,31 +125,35 @@
- {output.date.formatted}
+ {output.date?.formatted}
{output.network && (
- {getNetworkIcon()}
+ {getNetworkIcon(output.network)}
{output.network.defaultGateway?.ssid}
)}
-
-
- {Math.round(output.memory.usage)}%
-
+ {output.memory && (
+
+
+ {Math.round(output.memory.usage)}%
+
+ )}
-
-
+ {output.cpu && (
+
+
- {/* Change the text color if the CPU usage is high. */}
- 85 ? 'high-usage' : ''}
- >
- {Math.round(output.cpu.usage)}%
-
-
+ {/* Change the text color if the CPU usage is high. */}
+
85 ? 'high-usage' : ''}
+ >
+ {Math.round(output.cpu.usage)}%
+
+
+ )}
{output.battery && (
@@ -157,14 +161,14 @@
{output.battery.isCharging && (
)}
- {getBatteryIcon()}
+ {getBatteryIcon(output.battery)}
{Math.round(output.battery.chargePercent)}%
)}
{output.weather && (
- {getWeatherIcon()}
+ {getWeatherIcon(output.weather)}
{Math.round(output.weather.celsiusTemp)}°C
)}
diff --git a/examples/starter/with-glazewm.html b/examples/starter/with-glazewm.html
index c8ac35ba..b3b5d6c5 100644
--- a/examples/starter/with-glazewm.html
+++ b/examples/starter/with-glazewm.html
@@ -28,7 +28,7 @@
import { createRoot } from 'https://esm.sh/react-dom@18/client?dev';
import * as zebar from 'https://esm.sh/zebar@2';
- const providers = await zebar.createProviderGroup({
+ const providers = zebar.createProviderGroup({
network: { type: 'network' },
glazewm: { type: 'glazewm' },
cpu: { type: 'cpu' },
@@ -48,23 +48,23 @@
}, []);
// Get icon to show for current network status.
- function getNetworkIcon() {
- switch (output.network.defaultInterface?.type) {
+ function getNetworkIcon(networkOutput) {
+ switch (networkOutput.defaultInterface?.type) {
case 'ethernet':
return
;
case 'wifi':
- if (output.network.defaultGateway?.signalStrength >= 80) {
+ if (networkOutput.defaultGateway?.signalStrength >= 80) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 65
+ networkOutput.defaultGateway?.signalStrength >= 65
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 40
+ networkOutput.defaultGateway?.signalStrength >= 40
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 25
+ networkOutput.defaultGateway?.signalStrength >= 25
) {
return
;
} else {
@@ -78,21 +78,21 @@
}
// Get icon to show for how much of the battery is charged.
- function getBatteryIcon() {
- if (output.battery.chargePercent > 90)
+ function getBatteryIcon(batteryOutput) {
+ if (batteryOutput.chargePercent > 90)
return
;
- if (output.battery.chargePercent > 70)
+ if (batteryOutput.chargePercent > 70)
return
;
- if (output.battery.chargePercent > 40)
+ if (batteryOutput.chargePercent > 40)
return
;
- if (output.battery.chargePercent > 20)
+ if (batteryOutput.chargePercent > 20)
return
;
return
;
}
// Get icon to show for current weather status.
- function getWeatherIcon() {
- switch (output.weather.status) {
+ function getWeatherIcon(weatherOutput) {
+ switch (weatherOutput.status) {
case 'clear_day':
return
;
case 'clear_night':
@@ -143,7 +143,7 @@
)}
- {output.date.formatted}
+ {output.date?.formatted}
{output.glazewm && (
@@ -160,7 +160,7 @@
>
@@ -168,26 +168,30 @@
{output.network && (
- {getNetworkIcon()}
+ {getNetworkIcon(output.network)}
{output.network.defaultGateway?.ssid}
)}
-
-
- {Math.round(output.memory.usage)}%
-
+ {output.memory && (
+
+
+ {Math.round(output.memory.usage)}%
+
+ )}
-
-
+ {output.cpu && (
+
+
- {/* Change the text color if the CPU usage is high. */}
- 85 ? 'high-usage' : ''}
- >
- {Math.round(output.cpu.usage)}%
-
-
+ {/* Change the text color if the CPU usage is high. */}
+
85 ? 'high-usage' : ''}
+ >
+ {Math.round(output.cpu.usage)}%
+
+
+ )}
{output.battery && (
@@ -195,14 +199,14 @@
{output.battery.isCharging && (
)}
- {getBatteryIcon()}
+ {getBatteryIcon(output.battery)}
{Math.round(output.battery.chargePercent)}%
)}
{output.weather && (
- {getWeatherIcon()}
+ {getWeatherIcon(output.weather)}
{Math.round(output.weather.celsiusTemp)}°C
)}
diff --git a/examples/starter/with-komorebi.html b/examples/starter/with-komorebi.html
index 3aa9b8fb..8473794e 100644
--- a/examples/starter/with-komorebi.html
+++ b/examples/starter/with-komorebi.html
@@ -28,7 +28,7 @@
import { createRoot } from 'https://esm.sh/react-dom@18/client?dev';
import * as zebar from 'https://esm.sh/zebar@2';
- const providers = await zebar.createProviderGroup({
+ const providers = zebar.createProviderGroup({
network: { type: 'network' },
komorebi: { type: 'komorebi' },
cpu: { type: 'cpu' },
@@ -48,23 +48,23 @@
}, []);
// Get icon to show for current network status.
- function getNetworkIcon() {
- switch (output.network.defaultInterface?.type) {
+ function getNetworkIcon(networkOutput) {
+ switch (networkOutput.defaultInterface?.type) {
case 'ethernet':
return
;
case 'wifi':
- if (output.network.defaultGateway?.signalStrength >= 80) {
+ if (networkOutput.defaultGateway?.signalStrength >= 80) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 65
+ networkOutput.defaultGateway?.signalStrength >= 65
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 40
+ networkOutput.defaultGateway?.signalStrength >= 40
) {
return
;
} else if (
- output.network.defaultGateway?.signalStrength >= 25
+ networkOutput.defaultGateway?.signalStrength >= 25
) {
return
;
} else {
@@ -78,21 +78,21 @@
}
// Get icon to show for how much of the battery is charged.
- function getBatteryIcon() {
- if (output.battery.chargePercent > 90)
+ function getBatteryIcon(batteryOutput) {
+ if (batteryOutput.chargePercent > 90)
return
;
- if (output.battery.chargePercent > 70)
+ if (batteryOutput.chargePercent > 70)
return
;
- if (output.battery.chargePercent > 40)
+ if (batteryOutput.chargePercent > 40)
return
;
- if (output.battery.chargePercent > 20)
+ if (batteryOutput.chargePercent > 20)
return
;
return
;
}
// Get icon to show for current weather status.
- function getWeatherIcon() {
- switch (output.weather.status) {
+ function getWeatherIcon(weatherOutput) {
+ switch (weatherOutput.status) {
case 'clear_day':
return
;
case 'clear_night':
@@ -139,31 +139,35 @@
)}
- {output.date.formatted}
+ {output.date?.formatted}
{output.network && (
- {getNetworkIcon()}
+ {getNetworkIcon(output.network)}
{output.network.defaultGateway?.ssid}
)}
-
-
- {Math.round(output.memory.usage)}%
-
+ {output.memory && (
+
+
+ {Math.round(output.memory.usage)}%
+
+ )}
-
-
+ {output.cpu && (
+
+
- {/* Change the text color if the CPU usage is high. */}
- 85 ? 'high-usage' : ''}
- >
- {Math.round(output.cpu.usage)}%
-
-
+ {/* Change the text color if the CPU usage is high. */}
+
85 ? 'high-usage' : ''}
+ >
+ {Math.round(output.cpu.usage)}%
+
+
+ )}
{output.battery && (
@@ -171,14 +175,14 @@
{output.battery.isCharging && (
)}
- {getBatteryIcon()}
+ {getBatteryIcon(output.battery)}
{Math.round(output.battery.chargePercent)}%
)}
{output.weather && (
- {getWeatherIcon()}
+ {getWeatherIcon(output.weather)}
{Math.round(output.weather.celsiusTemp)}°C
)}
diff --git a/packages/client-api/src/providers/battery/create-battery-provider.ts b/packages/client-api/src/providers/battery/create-battery-provider.ts
index d1b43807..73a676b3 100644
--- a/packages/client-api/src/providers/battery/create-battery-provider.ts
+++ b/packages/client-api/src/providers/battery/create-battery-provider.ts
@@ -37,9 +37,9 @@ export interface BatteryOutput {
voltage: number | null;
}
-export async function createBatteryProvider(
+export function createBatteryProvider(
config: BatteryProviderConfig,
-): Promise
{
+): BatteryProvider {
const mergedConfig = batteryProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/cpu/create-cpu-provider.ts b/packages/client-api/src/providers/cpu/create-cpu-provider.ts
index 9716e2bb..d9377fde 100644
--- a/packages/client-api/src/providers/cpu/create-cpu-provider.ts
+++ b/packages/client-api/src/providers/cpu/create-cpu-provider.ts
@@ -30,9 +30,7 @@ export interface CpuOutput {
vendor: string;
}
-export async function createCpuProvider(
- config: CpuProviderConfig,
-): Promise {
+export function createCpuProvider(config: CpuProviderConfig): CpuProvider {
const mergedConfig = cpuProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/create-base-provider.ts b/packages/client-api/src/providers/create-base-provider.ts
index 59a2a3af..b31997cd 100644
--- a/packages/client-api/src/providers/create-base-provider.ts
+++ b/packages/client-api/src/providers/create-base-provider.ts
@@ -1,4 +1,3 @@
-import { Deferred } from '~/utils';
import type { ProviderConfig } from './create-provider';
export interface Provider {
@@ -52,6 +51,7 @@ export interface Provider {
}
type UnlistenFn = () => void | Promise;
+// type UnlistenFn = () => Promise;
/**
* Fetches next output or error from the provider.
@@ -59,15 +59,15 @@ type UnlistenFn = () => void | Promise;
type ProviderFetcher = (queue: {
output: (nextOutput: T) => void;
error: (nextError: string) => void;
-}) => UnlistenFn | Promise;
+}) => Promise;
-export async function createBaseProvider<
+export function createBaseProvider<
TConfig extends ProviderConfig,
TOutput,
>(
config: TConfig,
fetcher: ProviderFetcher,
-): Promise> {
+): Provider {
const outputListeners = new Set<(output: TOutput) => void>();
const errorListeners = new Set<(error: string) => void>();
@@ -77,28 +77,19 @@ export async function createBaseProvider<
hasError: false,
};
- let unlisten: UnlistenFn | null = await startFetcher();
+ let unlisten: Promise | null = startFetcher();
- async function startFetcher() {
- const hasFirstEmit = new Deferred();
-
- const unlisten = await fetcher({
+ function startFetcher() {
+ return fetcher({
output: output => {
latestEmission = { output, error: null, hasError: false };
outputListeners.forEach(listener => listener(output));
- hasFirstEmit.resolve();
},
error: error => {
latestEmission = { output: null, error, hasError: true };
errorListeners.forEach(listener => listener(error));
- hasFirstEmit.resolve();
},
});
-
- // Wait for the first emission.
- await hasFirstEmit.promise;
-
- return unlisten;
}
return {
@@ -114,17 +105,22 @@ export async function createBaseProvider<
config,
restart: async () => {
if (unlisten) {
- await unlisten();
+ await (
+ await unlisten
+ )();
}
- await startFetcher();
+ unlisten = startFetcher();
},
stop: async () => {
outputListeners.clear();
errorListeners.clear();
if (unlisten) {
- await unlisten();
+ await (
+ await unlisten
+ )();
+ unlisten = null;
}
},
onOutput: callback => {
diff --git a/packages/client-api/src/providers/create-provider-group.ts b/packages/client-api/src/providers/create-provider-group.ts
index c3eda5d3..05296c04 100644
--- a/packages/client-api/src/providers/create-provider-group.ts
+++ b/packages/client-api/src/providers/create-provider-group.ts
@@ -83,9 +83,9 @@ export type ProviderGroup = {
* functions and variables that can change over time. Alternatively, a
* single provider can be created using {@link createProvider}.
*/
-export async function createProviderGroup(
+export function createProviderGroup(
configMap: T,
-): Promise> {
+): ProviderGroup {
const outputListeners = new Set<
(outputMap: ProviderGroup['outputMap']) => void
>();
@@ -94,15 +94,17 @@ export async function createProviderGroup(
(errorMap: ProviderGroup['errorMap']) => void
>();
- const providerMap = await createProviderMap(configMap);
+ const providerMap = createProviderMap(configMap);
- let outputMap = {} as ProviderGroup['outputMap'];
- let errorMap = {} as ProviderGroup['errorMap'];
+ let outputMap = Object.fromEntries(
+ Object.keys(providerMap).map(name => [name, null]),
+ ) as ProviderGroup['outputMap'];
- for (const [name, provider] of Object.entries(providerMap)) {
- outputMap = { ...outputMap, [name]: provider.output };
- errorMap = { ...errorMap, [name]: provider.error };
+ let errorMap = Object.fromEntries(
+ Object.keys(providerMap).map(name => [name, null]),
+ ) as ProviderGroup['errorMap'];
+ for (const [name, provider] of Object.entries(providerMap)) {
provider.onOutput(() => {
outputMap = { ...outputMap, [name]: provider.output };
errorMap = { ...errorMap, [name]: null };
@@ -150,14 +152,14 @@ export async function createProviderGroup(
};
}
-async function createProviderMap(
- configMap: T,
-) {
- const providerEntries = await Promise.all([
- ...Object.entries(configMap).map(async ([key, value]) => {
- return [key, await createProvider(value)] as const;
- }),
- ]);
-
- return Object.fromEntries(providerEntries) as ProviderGroup['raw'];
+/**
+ * Creates a map of names to provider instances.
+ */
+function createProviderMap(configMap: T) {
+ return Object.fromEntries(
+ Object.entries(configMap).map(([name, config]) => [
+ name,
+ createProvider(config),
+ ]),
+ ) as ProviderGroup['raw'];
}
diff --git a/packages/client-api/src/providers/create-provider.ts b/packages/client-api/src/providers/create-provider.ts
index 50592d92..b1ea4304 100644
--- a/packages/client-api/src/providers/create-provider.ts
+++ b/packages/client-api/src/providers/create-provider.ts
@@ -93,16 +93,15 @@ export type ProviderOutput = ProviderMap[keyof ProviderMap]['output'];
* that can change over time. Alternatively, multiple providers can be
* created using {@link createProviderGroup}.
*
- * Waits until the provider has emitted either its first output or first
- * error. The provider will continue to output until its `stop` function is
+ * The provider will continue to output until its `stop` function is
* called.
*
- * @throws If the provider config is invalid. *Does not throw* if the
- * provider's first emission is an error.
+ * @throws If the provider config is invalid. Errors are emitted via the
+ * `onError` method.
*/
export function createProvider(
config: T,
-): Promise {
+): ProviderMap[T['type']] {
switch (config.type) {
case 'battery':
return createBatteryProvider(config) as any;
diff --git a/packages/client-api/src/providers/date/create-date-provider.ts b/packages/client-api/src/providers/date/create-date-provider.ts
index 063614bd..3c71f799 100644
--- a/packages/client-api/src/providers/date/create-date-provider.ts
+++ b/packages/client-api/src/providers/date/create-date-provider.ts
@@ -80,12 +80,12 @@ export interface DateOutput {
iso: string;
}
-export async function createDateProvider(
+export function createDateProvider(
config: DateProviderConfig,
-): Promise {
+): DateProvider {
const mergedConfig = dateProviderConfigSchema.parse(config);
- return createBaseProvider(mergedConfig, queue => {
+ return createBaseProvider(mergedConfig, async queue => {
queue.output(getDateValue());
const interval = setInterval(
diff --git a/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts b/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts
index 1cf87e9a..28495974 100644
--- a/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts
+++ b/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts
@@ -103,9 +103,9 @@ export interface GlazeWmOutput {
): Promise;
}
-export async function createGlazeWmProvider(
+export function createGlazeWmProvider(
config: GlazeWmProviderConfig,
-): Promise {
+): GlazeWmProvider {
const mergedConfig = glazeWmProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/host/create-host-provider.ts b/packages/client-api/src/providers/host/create-host-provider.ts
index 77a1a21b..82a5689b 100644
--- a/packages/client-api/src/providers/host/create-host-provider.ts
+++ b/packages/client-api/src/providers/host/create-host-provider.ts
@@ -31,9 +31,9 @@ export interface HostOutput {
uptime: number;
}
-export async function createHostProvider(
+export function createHostProvider(
config: HostProviderConfig,
-): Promise {
+): HostProvider {
const mergedConfig = hostProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/ip/create-ip-provider.ts b/packages/client-api/src/providers/ip/create-ip-provider.ts
index 496ddce2..35cb76b4 100644
--- a/packages/client-api/src/providers/ip/create-ip-provider.ts
+++ b/packages/client-api/src/providers/ip/create-ip-provider.ts
@@ -30,9 +30,7 @@ export interface IpOutput {
approxLongitude: number;
}
-export async function createIpProvider(
- config: IpProviderConfig,
-): Promise {
+export function createIpProvider(config: IpProviderConfig): IpProvider {
const mergedConfig = ipProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/keyboard/create-keyboard-provider.ts b/packages/client-api/src/providers/keyboard/create-keyboard-provider.ts
index c48b24d0..8ee2b13e 100644
--- a/packages/client-api/src/providers/keyboard/create-keyboard-provider.ts
+++ b/packages/client-api/src/providers/keyboard/create-keyboard-provider.ts
@@ -29,9 +29,9 @@ export interface KeyboardOutput {
layout: string;
}
-export async function createKeyboardProvider(
+export function createKeyboardProvider(
config: KeyboardProviderConfig,
-): Promise {
+): KeyboardProvider {
const mergedConfig = keyboardProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts b/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts
index 4fe9422c..36bd8b8c 100644
--- a/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts
+++ b/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts
@@ -121,9 +121,9 @@ export type KomorebiLayoutFlip =
| 'vertical'
| 'horizontal_and_vertical';
-export async function createKomorebiProvider(
+export function createKomorebiProvider(
config: KomorebiProviderConfig,
-): Promise {
+): KomorebiProvider {
const mergedConfig = komorebiProviderConfigSchema.parse(config);
// TODO: Update state when monitors change.
diff --git a/packages/client-api/src/providers/memory/create-memory-provider.ts b/packages/client-api/src/providers/memory/create-memory-provider.ts
index 102bd69c..f365e40f 100644
--- a/packages/client-api/src/providers/memory/create-memory-provider.ts
+++ b/packages/client-api/src/providers/memory/create-memory-provider.ts
@@ -32,9 +32,9 @@ export interface MemoryOutput {
totalSwap: number;
}
-export async function createMemoryProvider(
+export function createMemoryProvider(
config: MemoryProviderConfig,
-): Promise {
+): MemoryProvider {
const mergedConfig = memoryProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/network/create-network-provider.ts b/packages/client-api/src/providers/network/create-network-provider.ts
index eba29b01..b240dcdc 100644
--- a/packages/client-api/src/providers/network/create-network-provider.ts
+++ b/packages/client-api/src/providers/network/create-network-provider.ts
@@ -88,9 +88,9 @@ export interface NetworkTrafficMeasure {
iecUnit: string;
}
-export async function createNetworkProvider(
+export function createNetworkProvider(
config: NetworkProviderConfig,
-): Promise {
+): NetworkProvider {
const mergedConfig = networkProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
diff --git a/packages/client-api/src/providers/weather/create-weather-provider.ts b/packages/client-api/src/providers/weather/create-weather-provider.ts
index 1c406195..53a81f38 100644
--- a/packages/client-api/src/providers/weather/create-weather-provider.ts
+++ b/packages/client-api/src/providers/weather/create-weather-provider.ts
@@ -50,33 +50,12 @@ export interface WeatherOutput {
windSpeed: number;
}
-export async function createWeatherProvider(
+export function createWeatherProvider(
config: WeatherProviderConfig,
-): Promise {
- let ipProvider: IpProvider | null = null;
-
- const mergedConfig: WeatherProviderConfig = {
- ...weatherProviderConfigSchema.parse(config),
- longitude:
- config.longitude ?? (await getIpProvider()).output?.approxLongitude,
- latitude:
- config.latitude ?? (await getIpProvider()).output?.approxLatitude,
- };
-
- async function getIpProvider() {
- return (
- ipProvider ?? (ipProvider = await createProvider({ type: 'ip' }))
- );
- }
+): WeatherProvider {
+ const mergedConfig = weatherProviderConfigSchema.parse(config);
return createBaseProvider(mergedConfig, async queue => {
- if (!mergedConfig.latitude || !mergedConfig.longitude) {
- queue.error(
- 'Failed to fetch estimate for latitude/longitude from IP address.',
- );
- return () => {};
- }
-
return onProviderEmit(mergedConfig, ({ result }) => {
if ('error' in result) {
queue.error(result.error);
diff --git a/packages/desktop/src/monitor_state.rs b/packages/desktop/src/monitor_state.rs
index 668dd8a5..c71afcb2 100644
--- a/packages/desktop/src/monitor_state.rs
+++ b/packages/desktop/src/monitor_state.rs
@@ -3,7 +3,7 @@ use std::{sync::Arc, time::Duration};
use serde::Serialize;
use tauri::AppHandle;
use tokio::{
- sync::{broadcast, Mutex, RwLock},
+ sync::{broadcast, RwLock},
task,
};
use tracing::info;
diff --git a/packages/desktop/src/providers/ip/ip_provider.rs b/packages/desktop/src/providers/ip/ip_provider.rs
index 590769ed..37b1cdac 100644
--- a/packages/desktop/src/providers/ip/ip_provider.rs
+++ b/packages/desktop/src/providers/ip/ip_provider.rs
@@ -38,7 +38,7 @@ impl IpProvider {
self.config.refresh_interval
}
- async fn run_interval(&self) -> anyhow::Result {
+ pub async fn run_interval(&self) -> anyhow::Result {
let res = self
.http_client
.get("https://ipinfo.io/json")
diff --git a/packages/desktop/src/providers/weather/weather_provider.rs b/packages/desktop/src/providers/weather/weather_provider.rs
index 24016b5d..8b57d300 100644
--- a/packages/desktop/src/providers/weather/weather_provider.rs
+++ b/packages/desktop/src/providers/weather/weather_provider.rs
@@ -2,14 +2,20 @@ use reqwest::Client;
use serde::{Deserialize, Serialize};
use super::open_meteo_res::OpenMeteoRes;
-use crate::{impl_interval_provider, providers::ProviderOutput};
+use crate::{
+ impl_interval_provider,
+ providers::{
+ ip::{IpProvider, IpProviderConfig},
+ ProviderOutput,
+ },
+};
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct WeatherProviderConfig {
pub refresh_interval: u64,
- pub latitude: f32,
- pub longitude: f32,
+ pub latitude: Option,
+ pub longitude: Option,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
@@ -57,13 +63,33 @@ impl WeatherProvider {
}
async fn run_interval(&self) -> anyhow::Result {
+ let (latitude, longitude) = {
+ match (self.config.latitude, self.config.longitude) {
+ (Some(lat), Some(lon)) => (lat, lon),
+ _ => {
+ let ip_output = IpProvider::new(IpProviderConfig {
+ refresh_interval: 0,
+ })
+ .run_interval()
+ .await?;
+
+ match ip_output {
+ ProviderOutput::Ip(ip_output) => {
+ (ip_output.approx_latitude, ip_output.approx_longitude)
+ }
+ _ => anyhow::bail!("Unexpected output from IP provider."),
+ }
+ }
+ }
+ };
+
let res = self
.http_client
.get("https://api.open-meteo.com/v1/forecast")
.query(&[
("temperature_unit", "celsius"),
- ("latitude", &self.config.latitude.to_string()),
- ("longitude", &self.config.longitude.to_string()),
+ ("latitude", &latitude.to_string()),
+ ("longitude", &longitude.to_string()),
("current_weather", "true"),
("daily", "sunset,sunrise"),
("timezone", "auto"),