addon.cpp

// addon.cpp

#include <node.h>
#import <Foundation/Foundation.h>

using namespace v8;

void HideElectronWindow(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();

    // Extract the window ID from JavaScript arguments
    if (args.Length() < 1 || !args[0]->IsString()) {
        isolate->ThrowException(Exception::TypeError(
            String::NewFromUtf8(isolate, "Invalid arguments. Expected a window ID as a string.")));
        return;
    }

    String::Utf8Value windowIdArg(args[0]->ToString());
    const char* windowId = *windowIdArg;

    // Load the Swift module
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *swiftModulePath = [bundle pathForResource:@"ScreenShareHelper" ofType:@"xcframework"];
    NSBundle *swiftModuleBundle = [NSBundle bundleWithPath:swiftModulePath];
    [swiftModuleBundle load];

    // Call the Swift function with the window ID
    Class ScreenShareHelperClass = NSClassFromString(@"ScreenShareHelper");
    id screenShareHelperInstance = [[ScreenShareHelperClass alloc] init];

    SEL hideWindowSelector = NSSelectorFromString(@"hideElectronWindow:");
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                                [screenShareHelperInstance methodSignatureForSelector:hideWindowSelector]];
    [invocation setSelector:hideWindowSelector];
    [invocation setTarget:screenShareHelperInstance];
    [invocation setArgument:&windowId atIndex:2];  // 0 and 1 are reserved for target and selector

    [invocation invoke];

    // Return success to JavaScript
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Electron window hidden during screen share."));
}

void Initialize(Local<Object> exports) {
    NODE_SET_METHOD(exports, "hideElectronWindow", HideElectronWindow);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
  • create swift module

// ScreenShareHelper.swift

import Cocoa

public class ScreenShareHelper {
    public init() {}

    public func hideElectronWindow(windowId: String) {
        print("Hiding Electron window with ID: \(windowId)")

        // Assuming 'windowId' is the native window handle or identifier
        if let window = NSApp.window(withWindowNumber: Int(windowId)) {
            window.orderOut(nil)
        }
    }
}
  • swift build --product ScreenShareHelper -c release

import AppKit

// Assuming window is your NSWindow instance
if let window = yourWindow {
    window.sharingType = NSWindowSharingType(rawValue: 0)
}
// Package.swift

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "ScreenShareHelper",
    platforms: [
        .macOS(.v10_12),
    ],
    products: [
        .library(
            name: "ScreenShareHelper",
            targets: ["ScreenShareHelper"]),
    ],
    targets: [
        .target(
            name: "ScreenShareHelper",
            dependencies: []),
    ]
)

project-root/
|-- electron-app/
|   |-- main.js
|   |-- index.html
|   |-- package.json
|   |-- node_modules/
|   |   |-- ... (Electron dependencies)
|-- node-addon/
|   |-- binding.gyp
|   |-- addon.cpp
|   |-- build/
|   |   |-- Release/
|   |       |-- node-addon.node
|   |-- ScreenShareHelper.xcframework/
|       |-- ... (Swift module content)
|-- swift-package/
|   |-- Package.swift
|   |-- Sources/
|   |   |-- ScreenShareHelper/
|   |       |-- ScreenShareHelper.swift
|-- build/
|   |-- ... (Build artifacts, generated automatically)


Slot checking

To achieve your requirement, you need to create a database schema to store users, their availability, and slots. Here's how you can structure your tables and write the necessary backend logic to support this:

Database Schema

  1. Users Table This table will store user information.

sql Copy code CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, username VARCHAR(255) NOT NULL UNIQUE, name VARCHAR(255) NOT NULL, completed_onboarding BOOLEAN NOT NULL, time_zone VARCHAR(50) NOT NULL ); 2. Slots Table This table will store the time slots for availability.

sql Copy code CREATE TABLE slots ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id), start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, available BOOLEAN NOT NULL DEFAULT TRUE ); 3. Aggregated Slots Table This table will store aggregated slots for all users.

sql Copy code CREATE TABLE aggregated_slots ( id SERIAL PRIMARY KEY, start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, available_users INT NOT NULL DEFAULT 0 ); Backend Logic

  1. Checking Slots and Aggregating You need a function to check the slots for each user and then aggregate the results.

typescript Copy code import { PrismaClient } from '@prisma/client'; import dayjs from 'dayjs';

const prisma = new PrismaClient();

async function checkUserSlots(userId: number, startTime: Date, endTime: Date) { // Assume getUserAvailability is a function that returns availability for the user in the given time range const slots = await getUserAvailability(userId, startTime, endTime); return slots; }

async function getUserAvailability(userId: number, startTime: Date, endTime: Date) { // Simulated function to get user availability const slots = []; let currentTime = dayjs(startTime); const endDate = dayjs(endTime);

while (currentTime.isBefore(endDate)) { slots.push({ userId, start_time: currentTime.toDate(), end_time: currentTime.add(30, 'minute').toDate(), available: Math.random() > 0.5 // Randomly simulate availability }); currentTime = currentTime.add(30, 'minute'); }

return slots; }

async function aggregateSlotsForUsers(userIds: number[], startTime: Date, endTime: Date) { const allSlots = []; for (const userId of userIds) { const userSlots = await checkUserSlots(userId, startTime, endTime); allSlots.push(...userSlots); }

const aggregatedSlots = allSlots.reduce((acc, slot) => { const key = ${slot.start_time.toISOString()}_${slot.end_time.toISOString()}; if (!acc[key]) { acc[key] = { start_time: slot.start_time, end_time: slot.end_time, available_users: 0 }; } if (slot.available) { acc[key].available_users += 1; } return acc; }, {});

// Save aggregated slots to the database for (const key in aggregatedSlots) { const slot = aggregatedSlots[key]; await prisma.aggregated_slots.upsert({ where: { start_time_end_time: { start_time: slot.start_time, end_time: slot.end_time } }, update: { available_users: slot.available_users }, create: { start_time: slot.start_time, end_time: slot.end_time, available_users: slot.available_users } }); } }

// Example cron job function async function cronJob() { const users = await prisma.users.findMany(); const userIds = users.map(user => user.id);

const startTime = new Date(); // Current date const endTime = dayjs(startTime).add(7, 'days').toDate(); // 7 days from now

await aggregateSlotsForUsers(userIds, startTime, endTime); }

// Run the cron job cronJob().catch(console.error).finally(() => prisma.$disconnect()); 2. Fetching Available Slots for Frontend You need a function to fetch the available slots for the frontend based on the date range provided.

typescript Copy code import { PrismaClient } from '@prisma/client'; import dayjs from 'dayjs';

const prisma = new PrismaClient();

async function getAvailableSlots(startDate: Date, endDate: Date) { const slots = await prisma.aggregated_slots.findMany({ where: { start_time: { gte: startDate, lte: endDate }, available_users: { gt: 0 // Only fetch slots where at least one user is available } } });

return slots.map(slot => ({ start_time: slot.start_time, end_time: slot.end_time, available_users: slot.available_users })); }

// Example API handler async function apiHandler(req, res) { const { startDate, endDate } = req.query; const start = new Date(startDate); const end = new Date(endDate);

const availableSlots = await getAvailableSlots(start, end); res.json({ slots: availableSlots }); }

// Example usage apiHandler({ query: { startDate: '2024-07-01', endDate: '2024-07-08' } }, { json: (data) => console.log(data) }).catch(console.error).finally(() => prisma.$disconnect()); Summary Database Schema: Create tables for users, slots, and aggregated slots. Backend Logic: Implement functions to check user slots, aggregate the results, and save them in the database. Cron Job: Set up a cron job to run the slot checking and aggregation periodically. API Handler: Implement an API handler to fetch and return available slots to the frontend based on the provided date range. This approach ensures that your frontend can retrieve available slots efficiently, and your backend can manage and aggregate slot availability for multiple users.