Adds GameSave.sha1 to sync hash between devices
Fixes redundant record uploads post-sync due to comparing hashes against locally-cached hash via extended attributes.
This commit is contained in:
parent
707116a39b
commit
15e228f287
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
@ -160,7 +160,6 @@
|
||||
BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */; };
|
||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */; };
|
||||
BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFFA71E01AAC406100EE9DD1 /* Main.storyboard */; };
|
||||
BFFBD3D9224A0756002EFC79 /* URL+ExtendedAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFBD3D8224A0756002EFC79 /* URL+ExtendedAttributes.swift */; };
|
||||
BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFC461B1D59823500AF2CC6 /* GamesPresentationController.swift */; };
|
||||
BFFC461F1D59823500AF2CC6 /* GamesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFC461C1D59823500AF2CC6 /* GamesStoryboardSegue.swift */; };
|
||||
BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFC461D1D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift */; };
|
||||
@ -422,7 +421,6 @@
|
||||
BFFA71DB1AAC406100EE9DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
BFFA71E11AAC406100EE9DD1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
BFFBD3D8224A0756002EFC79 /* URL+ExtendedAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+ExtendedAttributes.swift"; sourceTree = "<group>"; };
|
||||
BFFC461B1D59823500AF2CC6 /* GamesPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesPresentationController.swift; sourceTree = "<group>"; };
|
||||
BFFC461C1D59823500AF2CC6 /* GamesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesStoryboardSegue.swift; sourceTree = "<group>"; };
|
||||
BFFC461D1D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialGamesStoryboardSegue.swift; sourceTree = "<group>"; };
|
||||
@ -536,7 +534,6 @@
|
||||
BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */,
|
||||
BFC3627F21ADE2BA00EF2BE6 /* UIAlertController+Error.swift */,
|
||||
BF1F45AC21AF57BA00EF9895 /* HarmonyMetadataKey+Keys.swift */,
|
||||
BFFBD3D8224A0756002EFC79 /* URL+ExtendedAttributes.swift */,
|
||||
BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */,
|
||||
BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */,
|
||||
BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */,
|
||||
@ -1611,7 +1608,6 @@
|
||||
BF4828861F9028F500028B97 /* System.swift in Sources */,
|
||||
BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */,
|
||||
BF6866171DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift in Sources */,
|
||||
BFFBD3D9224A0756002EFC79 /* URL+ExtendedAttributes.swift in Sources */,
|
||||
BF713C0822499ED4004A1A2B /* PreviousHarmony.xcdatamodeld in Sources */,
|
||||
BF59427D1E09BC830051894B /* ControllerSkin.swift in Sources */,
|
||||
BFAB9F7D219A43380080EC7D /* SyncManager.swift in Sources */,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19E287" minimumToolsVersion="Xcode 7.0" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="1.0">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22158.8" systemVersion="22F66" minimumToolsVersion="Xcode 7.0" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="1.0">
|
||||
<entity name="Cheat" representedClassName="Cheat" syncable="YES">
|
||||
<attribute name="code" attributeType="String" syncable="YES"/>
|
||||
<attribute name="creationDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||
@ -117,6 +117,7 @@
|
||||
<entity name="GameSave" representedClassName="GameSave" syncable="YES">
|
||||
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||
<attribute name="modifiedDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="sha1" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<relationship name="game" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Game" inverseName="gameSave" inverseEntity="Game" syncable="YES"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
@ -148,13 +149,4 @@
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Cheat" positionX="-198" positionY="-63" width="128" height="165"/>
|
||||
<element name="ControllerSkin" positionX="-387" positionY="90" width="128" height="163"/>
|
||||
<element name="Game" positionX="-378" positionY="-54" width="128" height="238"/>
|
||||
<element name="GameCollection" positionX="-585" positionY="-27" width="128" height="90"/>
|
||||
<element name="GameControllerInputMapping" positionX="-387" positionY="90" width="128" height="120"/>
|
||||
<element name="GameSave" positionX="-387" positionY="90" width="128" height="90"/>
|
||||
<element name="SaveState" positionX="-198" positionY="113" width="128" height="178"/>
|
||||
</elements>
|
||||
</model>
|
||||
@ -30,7 +30,7 @@ extension GameSave: Syncable
|
||||
}
|
||||
|
||||
public var syncableKeys: Set<AnyKeyPath> {
|
||||
return [\GameSave.modifiedDate]
|
||||
return [\GameSave.modifiedDate, \GameSave.sha1]
|
||||
}
|
||||
|
||||
public var syncableRelationships: Set<AnyKeyPath> {
|
||||
|
||||
@ -18,6 +18,8 @@ public class _GameSave: NSManagedObject
|
||||
|
||||
@NSManaged public var modifiedDate: Date
|
||||
|
||||
@NSManaged public var sha1: String?
|
||||
|
||||
// MARK: - Relationships
|
||||
|
||||
@NSManaged public var game: Game?
|
||||
|
||||
@ -755,23 +755,25 @@ private extension GameViewController
|
||||
let game = context.object(with: game.objectID) as! Game
|
||||
|
||||
let hash = try RSTHasher.sha1HashOfFile(at: game.gameSaveURL)
|
||||
let previousHash = game.gameSaveURL.extendedAttribute(name: "com.rileytestut.delta.sha1Hash")
|
||||
let previousHash = game.gameSave?.sha1
|
||||
|
||||
guard hash != previousHash else { return }
|
||||
|
||||
if let gameSave = game.gameSave
|
||||
{
|
||||
gameSave.modifiedDate = Date()
|
||||
gameSave.sha1 = hash
|
||||
}
|
||||
else
|
||||
{
|
||||
let gameSave = GameSave(context: context)
|
||||
gameSave.identifier = game.identifier
|
||||
gameSave.sha1 = hash
|
||||
|
||||
game.gameSave = gameSave
|
||||
}
|
||||
|
||||
try context.save()
|
||||
try game.gameSaveURL.setExtendedAttribute(name: "com.rileytestut.delta.sha1Hash", value: hash)
|
||||
|
||||
if ExperimentalFeatures.shared.toastNotifications.gameSaveEnabled
|
||||
{
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
//
|
||||
// URL+ExtendedAttributes.swift
|
||||
// Delta
|
||||
//
|
||||
// Created by Riley Testut on 3/26/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension URL
|
||||
{
|
||||
func setExtendedAttribute(name: String, value: String) throws
|
||||
{
|
||||
try self.withUnsafeFileSystemRepresentation { (path) in
|
||||
let data = value.data(using: .utf8)
|
||||
let result = data?.withUnsafeBytes { (buffer) in
|
||||
setxattr(path, name, buffer.baseAddress, buffer.count, 0, 0)
|
||||
}
|
||||
|
||||
if let result = result, result < 0
|
||||
{
|
||||
throw POSIXError(POSIXErrorCode(rawValue: errno) ?? .ENOENT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extendedAttribute(name: String) -> String?
|
||||
{
|
||||
let value = self.withUnsafeFileSystemRepresentation { (path) -> String? in
|
||||
let size = getxattr(path, name, nil, 0, 0, 0)
|
||||
guard size >= 0 else { return nil }
|
||||
|
||||
var data = Data(count: size)
|
||||
let result = data.withUnsafeMutableBytes { getxattr(path, name, $0.baseAddress, $0.count, 0, 0) }
|
||||
|
||||
guard result >= 0 else { return nil }
|
||||
|
||||
let value = String(data: data, encoding: .utf8)!
|
||||
return value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user