Add Hotspot implementation

This commit is contained in:
Balazs Perlaki-Horvath 2025-07-04 23:08:24 +02:00 committed by Kelson
parent 9fd8378de0
commit e0b9b19059
8 changed files with 138 additions and 7 deletions

View File

@ -21,12 +21,33 @@ final class Hotspot: ObservableObject {
@MainActor
static let shared = Hotspot()
@ZimActor
private var hotspot: KiwixHotspot?
@Published private(set) var isStarted: Bool = false
@Published var selection = MultiSelectedZimFilesViewModel()
@MainActor
func toggle() {
isStarted = !isStarted
@ZimActor
func toggle() async {
if let hotspot {
hotspot.__stop()
self.hotspot = nil
await MainActor.run { self.isStarted = false }
return
} else {
let zimFileIds: Set<UUID> = await MainActor.run(resultType: Set<UUID>.self, body: {
Set(selection.selectedZimFiles.map{ $0.fileID })
})
guard !zimFileIds.isEmpty else {
debugPrint("no zim files were set for Hotspot to start")
return
}
self.hotspot = KiwixHotspot(__zimFileIds: zimFileIds)
await MainActor.run {
isStarted = true
debugPrint("current IP: \(Self.wifiIPaddress())")
}
}
}
static func wifiIPaddress() -> String {

View File

@ -0,0 +1,26 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#import <Foundation/Foundation.h>
#import "kiwix/library.h"
@interface KiwixHotspot : NSObject
- (nonnull KiwixHotspot *)initWithZimFileIds:(NSSet *_Nonnull) zimFileIDs NS_REFINED_FOR_SWIFT;
//- (void)start;
- (void) stop NS_REFINED_FOR_SWIFT;
@end

View File

@ -0,0 +1,80 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#pragma clang diagnostic pop
#import <Foundation/Foundation.h>
#import "KiwixHotspot.h"
#import "zim/archive.h"
#import "kiwix/library.h"
#import "kiwix/book.h"
#import "kiwix/server.h"
#import "ZimFileService.h"
@interface KiwixHotspot ()
@property kiwix::LibraryPtr library;
@property std::shared_ptr<kiwix::Server> server;
//@property kiwix::Server server;
@end
@implementation KiwixHotspot
- (KiwixHotspot *)initWithZimFileIds:(nonnull NSSet *)zimFileIDs {
self = [super init];
if (self) {
self.library = kiwix::Library::create();
if(self.library != nullptr) {
[self startFor:zimFileIDs];
} else {
NSLog(@"couldn't create kiwix::Library for Hotspot!");
}
}
return self;
}
-(void) startFor: (nonnull NSSet *) zimFileIDs {
if (self.server != nullptr) {
self.server = nil;
}
for (NSUUID *zimFileID in zimFileIDs) {
try {
zim::Archive * _Nullable archive = [[ZimFileService sharedInstance] findArchiveBy:zimFileID];
if(archive != nullptr) {
kiwix::Book book = kiwix::Book();
book.update(*archive);
self.library->addBook(book);
}
} catch (std::exception &e) {
NSLog(@"couldn't add zimFile to Hotspot: %@ because: %s", zimFileID, e.what());
}
}
self.server = std::make_shared<kiwix::Server>(self.library);
self.server->setPort(8080);
self.server->start();
}
- (void)stop {
if(self.server != nullptr) {
self.server->stop();
}
}
@end

View File

@ -15,6 +15,7 @@
#import <Foundation/Foundation.h>
#import "ZimFileMetaData.h"
#import "zim/archive.h"
@interface ZimFileService : NSObject
@ -30,6 +31,7 @@
- (NSUUID *_Nullable)open:(NSUUID *_Nonnull)zimFileID NS_REFINED_FOR_SWIFT;
- (void)close:(NSUUID *_Nonnull)zimFileID NS_REFINED_FOR_SWIFT;
- (NSArray *_Nonnull)getReaderIdentifiers NS_REFINED_FOR_SWIFT;
- (zim::Archive *_Nullable) findArchiveBy: (NSUUID *_Nonnull) zimFileID;
- (nonnull void *) getArchives;
# pragma mark - Metadata

View File

@ -7,6 +7,7 @@
#import "ZimFileMetaData.h"
#import "SearchOperation.h"
#import "SearchResult.h"
#import "KiwixHotspot.h"
NS_INLINE NSException * _Nullable objCTryBlock(void(^_Nonnull tryBlock)(void)) {

View File

@ -41,7 +41,7 @@ struct HotspotDetails: View {
.collapsible(false)
Section(LocalString.zim_file_list_actions_text) {
Action(title: buttonTitle) {
hotspot.toggle()
await hotspot.toggle()
}
.buttonStyle(.borderedProminent)
}
@ -52,7 +52,7 @@ struct HotspotDetails: View {
var body: some View {
Action(title: buttonTitle, isDestructive: hotspot.isStarted) {
hotspot.toggle()
await hotspot.toggle()
}
.buttonStyle(.borderedProminent)
.modifier(BadgeModifier(count: zimFiles.count))

View File

@ -93,8 +93,8 @@ struct HotspotZimFilesSelection: View {
#if os(iOS)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
hotspot.toggle()
AsyncButton {
await hotspot.toggle()
} label: {
let text = if hotspot.isStarted {
LocalString.hotspot_action_stop_server_title

View File

@ -61,6 +61,7 @@ targetTemplates:
com.apple.security.app-sandbox: true
com.apple.security.files.user-selected.read-write: true
com.apple.security.network.client: true
com.apple.security.network.server: true
com.apple.security.print: true
dependencies:
- framework: CoreKiwix.xcframework