Skip to content

Commit

Permalink
🚧🍃⚙️ Core hot reloading working, Prisma time
Browse files Browse the repository at this point in the history
  • Loading branch information
MulverineX committed Sep 9, 2023
1 parent bef1bb3 commit 7c7ee5c
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 108 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "1.0.0",
"license": "MIT",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"core-dev": "nodemon -w packages/core/ --esm scripts/dev.ts"
},
"workspaces": [
"packages/**"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_js/extensions/fetch.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:path/path.dart';
Expand All @@ -12,15 +13,66 @@ import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_router/shelf_router.dart' as shelf_router;

class AppCore {
late String appData;
// ignore: must_be_immutable
class AppCore extends InheritedWidget {
late String appDataDir;

late Database db;

late JavascriptRuntime core;

AppCore({
super.key,
required Widget child,
}) : super(child: child);

@override
bool updateShouldNotify(AppCore oldWidget) => core != oldWidget.core;

static AppCore? maybeOf(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppCore>();
}

static AppCore of(BuildContext context) {
final AppCore? result = maybeOf(context);
assert(result != null, 'No AppCore found in context');
return result!;
}

initCore(String bundle) async {
core = getJavascriptRuntime();

await core.enableFetch();

await core.enableHandlePromises();

final databaseInitialized = Completer();

core.onMessage('initDatabase', (sql) {
db.execute(sql);

databaseInitialized.complete();
});

core.onMessage('queryDatabase', (query) {
return db.query(query);
});

core.onMessage('print', (message) {
print(message);
});

await core.evaluateAsync("""
var connection_data = ${json.encode({"address": "http://localhost:4829"})};
""");

await core.evaluateAsync(bundle);

// await databaseInitialized.future;
}

Future<void> load() async {
appData = (await getApplicationSupportDirectory()).path;
appDataDir = (await getApplicationSupportDirectory()).path;

if (Platform.isWindows || Platform.isLinux) {
// Initialize FFI
Expand All @@ -30,7 +82,7 @@ class AppCore {
// this step, it will use the sqlite version available on the system.
databaseFactory = databaseFactoryFfi;

db = await openDatabase(join(appData, 'main.db'));
db = await openDatabase(join(appDataDir, 'main.db'));

// TODO: Add ability to run Refracture offline

Expand All @@ -42,9 +94,9 @@ class AppCore {

dynamic currentTag = false;

final tagFile = File(join(appData, 'core_tag'));
final tagFile = File(join(appDataDir, 'core_tag'));

final coreFile = File(join(appData, 'core'));
final coreFile = File(join(appDataDir, 'core'));

try {
currentTag = await tagFile.readAsString();
Expand All @@ -60,51 +112,10 @@ class AppCore {
bundle = await coreFile.readAsString();
}

core = getJavascriptRuntime();

await core.enableFetch();

await core.enableHandlePromises();

final databaseInitialized = Completer();

core.onMessage('initDatabase', (sql) {
db.execute(sql);

databaseInitialized.complete();
});

core.onMessage('queryDatabase', (query) {
return db.query(query);
});

core.onMessage('print', (message) {
print(message);
});

connectionData() async {
await core.evaluateAsync("""
var connection_data = ${json.encode({"address": "http://localhost:4829"})};
""");
}

await connectionData();

await core.evaluateAsync(bundle);

// await databaseInitialized.future;
initCore(bundle);

Future<Response> updateRes(Request req) async {
print('a');
core.dispose();

core = getJavascriptRuntime();

await connectionData();

final test = await utf8.decodeStream(req.read());

await core.evaluateAsync(test);
await initCore(await utf8.decodeStream(req.read()));

return Response(200);
}
Expand Down
8 changes: 2 additions & 6 deletions packages/client-flutter/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refracture_music/app/load_core.dart';
import 'package:refracture_music/app/core.dart';

import 'views/navigation.dart';

void main() {
runApp(const MusicApp());

final core = AppCore();

core.load();
runApp(AppCore(child: const MusicApp())..load());
}

class MusicApp extends StatelessWidget {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
# Keep environment variables out of version control
.env
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"homepage": "https://github.com/RefractureMedia/refracture-music#readme",
"devDependencies": {
"prisma": "^5.2.0",
"ts-loader": "^9.4.4",
"typescript": "^4.7.2",
"webpack": "^5.88.2",
Expand Down
34 changes: 34 additions & 0 deletions packages/core/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}

model Track {
id Int @id @default(autoincrement())
title String
duration BigInt
artists Artist[] @relation(fields: [name], references: [id])
album Album @relation(fields: [title, art], references: [id])
track_number Int
}

model Artist {
id Int @id @default(autoincrement())
profile_image String
name String
tracks Track[] @relation(fields: [title, duration, artists, album], references: [id])
}

model Album {
id Int @id @default(autoincrement())
title String
art String
artist Artist @relation(fields: [name], references: [id])
}
4 changes: 4 additions & 0 deletions packages/core/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @param message Must be valid JSON; '"Helooo"', JSON.stringify({blah: 'foo'}), etc.
*/
declare function sendMessage(channel_name: string, message: string): any;
7 changes: 2 additions & 5 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'react-native-polyfill';
import 'core-js/actual/url';
import 'core-js/actual/clearTimeout';
import { AccountManager, AccountClass } from './account/index';
import { ItemManager } from './media/index';
import Player from './player/index';
import { PluginManager } from './plugin/index';
import SessionManager from './session/index';
import { Logger } from './util/logging';

export class MusicCore {
session: SessionManager;
Expand Down Expand Up @@ -44,9 +44,6 @@ export class MusicCore {

export const Music = new MusicCore();

/**
* @param message Must be valid JSON; '"Helooo"', JSON.stringify({blah: 'foo'}), etc.
*/
declare function sendMessage(channel_name: string, message: string): any;
Logger.info('Hello World!')

export default Music;
46 changes: 0 additions & 46 deletions packages/core/src/todo_add_to_bundle

This file was deleted.

47 changes: 47 additions & 0 deletions packages/core/src/util/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class LoggerClass {
protected provider: (message: string) => void;

constructor() {
if (console) {
this.provider = (message) => console.log(message);
}
this.provider = (message) => sendMessage('print', `"${message}"`)
}

/**
* Temporary debug logging; remove before release!
*/
public debug(message: string) {
this.provider(`[Music Core: DEBUG] ${message}`)
}

/**
* Unable to operate; user should expect an unresponsive app.
*/
public fatal(error: string) {
this.provider(`[Music Core: FATAL] ${error}`)
}

/**
* Failure of function; user should expect broken features.
*/
public error(error: string) {
this.provider(`[Music Core: ERROR] ${error}`)
}

/**
* Unexpected/unideal result of function; this should usually not be used.
*/
public warn(warning: string) {
this.provider(`[Music Core: WARN] ${warning}`)
}

/**
* Normal operation.
*/
public info(info: string) {
this.provider(`[Music Core: INFO] ${info}`)
}
}

export const Logger = new LoggerClass()
Loading

0 comments on commit 7c7ee5c

Please sign in to comment.