Compare commits

...

4 Commits

Author SHA1 Message Date
Alex Tran
31739aca02 Up version for release 2022-09-10 11:58:59 -05:00
Thanh Pham
8f2e7b6f65 fix(server): loop on checksum generation (#662) 2022-09-10 11:52:39 -05:00
Brett Profitt
4ed647c43d fix(install): Fix checking for docker compose. (#663) 2022-09-10 11:48:50 -05:00
Alex
f88ff4fb5c fix(mobile): background backup not working in release mode (#664) 2022-09-10 11:46:51 -05:00
11 changed files with 76 additions and 41 deletions

View File

@@ -6,10 +6,6 @@ RED='\033[0;31m'
GREEN='\032[0;31m' GREEN='\032[0;31m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
machine_has() {
type "$1" >/dev/null 2>&1
}
create_immich_directory() { create_immich_directory() {
echo "Creating Immich directory..." echo "Creating Immich directory..."
mkdir -p ./immich-app/immich-data mkdir -p ./immich-app/immich-data
@@ -45,18 +41,21 @@ populate_upload_location() {
start_docker_compose() { start_docker_compose() {
echo "Starting Immich's docker containers" echo "Starting Immich's docker containers"
if machine_has "docker compose"; then { if docker compose &> /dev/null; then
docker compose up --remove-orphans -d docker_bin="docker compose"
elif docker-compose &> /dev/null; then
show_friendly_message docker_bin="docker-compose"
exit 0 else
}; fi echo 'Cannot find `docker compose` or `docker-compose`.'
exit 1
if machine_has "docker-compose"; then fi
docker-compose up --remove-orphans -d
if $docker_bin up --remove-orphans -d; then
show_friendly_message show_friendly_message
exit 0 exit 0
else
echo "Could not start. Check for errors above."
exit 1
fi fi
} }

View File

@@ -30,8 +30,8 @@ platform :android do
task: 'bundle', task: 'bundle',
build_type: 'Release', build_type: 'Release',
properties: { properties: {
"android.injected.version.code" => 39, "android.injected.version.code" => 40,
"android.injected.version.name" => "1.28.1", "android.injected.version.name" => "1.28.2",
} }
) )
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

View File

@@ -0,0 +1 @@
* Fix background service cannot run in release build

View File

@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta" desc "iOS Beta"
lane :beta do lane :beta do
increment_version_number( increment_version_number(
version_number: "1.28.1" version_number: "1.28.2"
) )
increment_build_number( increment_build_number(
build_number: latest_testflight_build_number + 1, build_number: latest_testflight_build_number + 1,

View File

@@ -173,7 +173,8 @@ class BackgroundService {
} }
} catch (error) { } catch (error) {
debugPrint( debugPrint(
"[_clearErrorNotifications] failed to communicate with plugin"); "[_clearErrorNotifications] failed to communicate with plugin",
);
} }
return false; return false;
} }
@@ -344,7 +345,9 @@ class BackgroundService {
} }
Future<bool> _runBackup( Future<bool> _runBackup(
BackupService backupService, HiveBackupAlbums backupAlbumInfo) async { BackupService backupService,
HiveBackupAlbums backupAlbumInfo,
) async {
_errorGracePeriodExceeded = _isErrorGracePeriodExceeded(); _errorGracePeriodExceeded = _isErrorGracePeriodExceeded();
if (_canceledBySystem) { if (_canceledBySystem) {
@@ -445,6 +448,7 @@ class BackgroundService {
} }
/// entry point called by Kotlin/Java code; needs to be a top-level function /// entry point called by Kotlin/Java code; needs to be a top-level function
@pragma('vm:entry-point')
void _nativeEntry() { void _nativeEntry() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
BackgroundService backgroundService = BackgroundService(); BackgroundService backgroundService = BackgroundService();

View File

@@ -173,19 +173,19 @@ class BackupControllerPage extends HookConsumerWidget {
).tr(), ).tr(),
), ),
actions: [ actions: [
TextButton( OutlinedButton(
onPressed: () => launchUrl( onPressed: () => launchUrl(
Uri.parse('https://dontkillmyapp.com'), Uri.parse('https://dontkillmyapp.com'),
mode: LaunchMode.externalApplication), mode: LaunchMode.externalApplication,
child: Text( ),
child: const Text(
"backup_controller_page_background_battery_info_link", "backup_controller_page_background_battery_info_link",
style: TextStyle(color: buttonTextColor),
).tr(), ).tr(),
), ),
TextButton( ElevatedButton(
child: Text( child: const Text(
'backup_controller_page_background_battery_info_ok', 'backup_controller_page_background_battery_info_ok',
style: TextStyle(color: buttonTextColor), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
).tr(), ).tr(),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
@@ -636,8 +636,8 @@ class BackupControllerPage extends HookConsumerWidget {
backupState.backupProgress == BackUpProgressEnum.inProgress backupState.backupProgress == BackUpProgressEnum.inProgress
? ElevatedButton( ? ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
primary: Colors.red[300], foregroundColor: Colors.grey[50],
onPrimary: Colors.grey[50], backgroundColor: Colors.red[300],
// padding: const EdgeInsets.all(14), // padding: const EdgeInsets.all(14),
), ),
onPressed: () { onPressed: () {

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone description: Immich - selfhosted backup media file on mobile phone
publish_to: "none" publish_to: "none"
version: 1.28.1+39 version: 1.28.2+40
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"

View File

@@ -11,6 +11,6 @@ export interface IServerVersion {
export const serverVersion: IServerVersion = { export const serverVersion: IServerVersion = {
major: 1, major: 1,
minor: 28, minor: 28,
patch: 1, patch: 2,
build: 39, build: 40,
}; };

View File

@@ -6,6 +6,7 @@ import cookieParser from 'cookie-parser';
import { writeFileSync } from 'fs'; import { writeFileSync } from 'fs';
import path from 'path'; import path from 'path';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { serverVersion } from './constants/server_version.constant';
import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware'; import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware';
async function bootstrap() { async function bootstrap() {
@@ -52,11 +53,17 @@ async function bootstrap() {
// Generate API Documentation only in development mode // Generate API Documentation only in development mode
const outputPath = path.resolve(process.cwd(), 'immich-openapi-specs.json'); const outputPath = path.resolve(process.cwd(), 'immich-openapi-specs.json');
writeFileSync(outputPath, JSON.stringify(apiDocument), { encoding: 'utf8' }); writeFileSync(outputPath, JSON.stringify(apiDocument), { encoding: 'utf8' });
Logger.log('Running Immich Server in DEVELOPMENT environment', 'ImmichServer'); Logger.log(
`Running Immich Server in DEVELOPMENT environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
'ImmichServer',
);
} }
if (process.env.NODE_ENV == 'production') { if (process.env.NODE_ENV == 'production') {
Logger.log('Running Immich Server in PRODUCTION environment', 'ImmichServer'); Logger.log(
`Running Immich Server in PRODUCTION environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
'ImmichServer',
);
} }
}); });
} }

View File

@@ -1,5 +1,6 @@
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { serverVersion } from 'apps/immich/src/constants/server_version.constant';
import { RedisIoAdapter } from '../../immich/src/middlewares/redis-io.adapter.middleware'; import { RedisIoAdapter } from '../../immich/src/middlewares/redis-io.adapter.middleware';
import { MicroservicesModule } from './microservices.module'; import { MicroservicesModule } from './microservices.module';
@@ -10,11 +11,17 @@ async function bootstrap() {
await app.listen(3002, () => { await app.listen(3002, () => {
if (process.env.NODE_ENV == 'development') { if (process.env.NODE_ENV == 'development') {
Logger.log('Running Immich Microservices in DEVELOPMENT environment', 'ImmichMicroservice'); Logger.log(
`Running Immich Microservices in DEVELOPMENT environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
'ImmichMicroservice',
);
} }
if (process.env.NODE_ENV == 'production') { if (process.env.NODE_ENV == 'production') {
Logger.log('Running Immich Microservices in PRODUCTION environment', 'ImmichMicroservice'); Logger.log(
`Running Immich Microservices in PRODUCTION environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
'ImmichMicroservice',
);
} }
}); });
} }

View File

@@ -5,7 +5,7 @@ import { Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { createHash } from 'node:crypto'; import { createHash } from 'node:crypto';
import fs from 'node:fs'; import fs from 'node:fs';
import { IsNull, Repository } from 'typeorm'; import { FindOptionsWhere, IsNull, MoreThan, QueryFailedError, Repository } from 'typeorm';
// TODO: just temporary task to generate previous uploaded assets. // TODO: just temporary task to generate previous uploaded assets.
@Processor(generateChecksumQueueName) @Processor(generateChecksumQueueName)
@@ -17,15 +17,23 @@ export class GenerateChecksumProcessor {
@Process() @Process()
async generateChecksum() { async generateChecksum() {
let hasNext = true;
const pageSize = 200; const pageSize = 200;
let hasNext = true;
let lastErrAssetId: string | undefined = undefined;
while (hasNext) { while (hasNext) {
const whereStat: FindOptionsWhere<AssetEntity> = {
checksum: IsNull(),
};
if (lastErrAssetId) {
whereStat.id = MoreThan(lastErrAssetId);
}
const assets = await this.assetRepository.find({ const assets = await this.assetRepository.find({
where: { where: whereStat,
checksum: IsNull()
},
take: pageSize, take: pageSize,
order: { id: 'ASC' }
}); });
if (!assets?.length) { if (!assets?.length) {
@@ -35,15 +43,24 @@ export class GenerateChecksumProcessor {
try { try {
await this.generateAssetChecksum(asset); await this.generateAssetChecksum(asset);
} catch (err: any) { } catch (err: any) {
Logger.error(`Error generate checksum ${err}`); lastErrAssetId = asset.id;
if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
Logger.error(`${asset.originalPath} duplicated`);
} else {
Logger.error(`checksum generation ${err}`);
}
} }
} }
// break when reach to the last page
if (assets.length < pageSize) { if (assets.length < pageSize) {
hasNext = false; hasNext = false;
} }
} }
} }
Logger.log(`checksum generation done!`);
} }
private async generateAssetChecksum(asset: AssetEntity) { private async generateAssetChecksum(asset: AssetEntity) {