mirror of
https://github.com/OpenFactorioServerManager/factorio-server-manager.git
synced 2025-01-10 04:19:38 +02:00
user-interface to show everything correctly without race-conditions
This commit is contained in:
parent
8179e2c917
commit
6b9639e927
@ -56,7 +56,6 @@ func (fl *FileLock) Lock(filePath string) error {
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("write locked")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -73,7 +72,6 @@ func (fl *FileLock) Unlock(filePath string) error {
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("write unlocked")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -90,7 +88,6 @@ func (fl *FileLock) RLock(filePath string) error {
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("read locked")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -107,15 +104,12 @@ func (fl *FileLock) RUnlock(filePath string) error {
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("read unlocked")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FileLock) LockW(filePath string) {
|
||||
log.Println("LockW called")
|
||||
for {
|
||||
err := fl.Lock(filePath)
|
||||
log.Println(err)
|
||||
if err == ErrorAlreadyLocked {
|
||||
time.Sleep(time.Second * 2)
|
||||
log.Println("file locked wait two seconds to access write-lock")
|
||||
@ -134,7 +128,7 @@ func (fl *FileLock) RLockW(filePath string) {
|
||||
|
||||
if err == ErrorAlreadyLocked {
|
||||
time.Sleep(time.Second * 2)
|
||||
log.Println("file locked wait two seconds to access read-lock")
|
||||
log.Println("file locked ... wait two seconds to try to access read-lock")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
|
@ -139,12 +139,14 @@ func (mod_simple_list *ModSimpleList) createMod(mod_name string) (error) {
|
||||
}
|
||||
|
||||
|
||||
func (mod_simple_list *ModSimpleList) toggleMod(mod_name string) error {
|
||||
func (mod_simple_list *ModSimpleList) toggleMod(mod_name string) (error, bool) {
|
||||
var err error
|
||||
var newEnabled bool
|
||||
|
||||
for index, mod := range mod_simple_list.Mods {
|
||||
if mod.Name == mod_name {
|
||||
mod_simple_list.Mods[index].Enabled = !mod_simple_list.Mods[index].Enabled
|
||||
newEnabled = !mod_simple_list.Mods[index].Enabled
|
||||
mod_simple_list.Mods[index].Enabled = newEnabled
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -152,10 +154,10 @@ func (mod_simple_list *ModSimpleList) toggleMod(mod_name string) error {
|
||||
err = mod_simple_list.saveModInfoJson()
|
||||
if err != nil {
|
||||
log.Printf("error on savin new ModSimpleList: %s", err)
|
||||
return err
|
||||
return err, newEnabled
|
||||
}
|
||||
|
||||
//i changed it already don't need to reload it
|
||||
|
||||
return nil
|
||||
return nil, newEnabled
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ func ToggleModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
mods, err := newMods(config.FactorioModsDir)
|
||||
if err == nil {
|
||||
err = mods.ModSimpleList.toggleMod(mod_name)
|
||||
err, resp.Data = mods.ModSimpleList.toggleMod(mod_name)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -251,7 +251,6 @@ func ToggleModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mods.listInstalledMods().ModsResult
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -284,7 +283,7 @@ func DeleteModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mods.listInstalledMods().ModsResult
|
||||
resp.Data = mod_name
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -341,7 +340,7 @@ func UpdateModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
resp.Data = fmt.Sprintf("Error in deleteMod: %s", err)
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
log.Printf("Error in DeleteModHandler: %s", err)
|
||||
@ -349,7 +348,13 @@ func UpdateModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mods.listInstalledMods()
|
||||
installedMods := mods.listInstalledMods().ModsResult
|
||||
for _, mod := range installedMods {
|
||||
if mod.Name == mod_name {
|
||||
resp.Data = mod
|
||||
break
|
||||
}
|
||||
}
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -537,7 +542,7 @@ func DeleteModPackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mod_pack_map.listInstalledModPacks()
|
||||
resp.Data = name
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -590,7 +595,7 @@ func ModPackToggleModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
mod_pack_map, err := newModPackMap()
|
||||
if err == nil {
|
||||
err = mod_pack_map[mod_pack_name].Mods.ModSimpleList.toggleMod(mod_name)
|
||||
err, resp.Data = mod_pack_map[mod_pack_name].Mods.ModSimpleList.toggleMod(mod_name)
|
||||
}
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@ -601,7 +606,6 @@ func ModPackToggleModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mod_pack_map.listInstalledModPacks()
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -637,7 +641,7 @@ func ModPackDeleteModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mod_pack_map.listInstalledModPacks()
|
||||
resp.Data = true
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
@ -679,7 +683,13 @@ func ModPackUpdateModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Data = mod_pack_map.listInstalledModPacks()
|
||||
installedMods := mod_pack_map[mod_pack_name].Mods.listInstalledMods().ModsResult
|
||||
for _, mod := range installedMods {
|
||||
if mod.Name == mod_name {
|
||||
resp.Data = mod
|
||||
break
|
||||
}
|
||||
}
|
||||
resp.Success = true
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
|
@ -125,7 +125,8 @@ class Mod extends React.Component {
|
||||
ref='modName'
|
||||
type='submit'
|
||||
value='Toggle'
|
||||
onClick={this.props.toggleMod}
|
||||
onClick={(event) => this.props.toggleMod(event, this.state.updateInProgress)}
|
||||
disabled={this.state.updateInProgress}
|
||||
/>
|
||||
|
||||
<input className="btn btn-danger btn-sm"
|
||||
@ -133,7 +134,8 @@ class Mod extends React.Component {
|
||||
ref="modName"
|
||||
type="submit"
|
||||
value="Delete"
|
||||
onClick={this.props.deleteMod}
|
||||
onClick={(event) => this.props.deleteMod(event, this.state.updateInProgress)}
|
||||
disabled={this.state.updateInProgress}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import ModManager from "../ModManager.jsx";
|
||||
import NativeListener from 'react-native-listener';
|
||||
import {instanceOfModsContent} from "../ModsPropTypes.js";
|
||||
import locks from "locks";
|
||||
|
||||
class ModPackOverview extends React.Component {
|
||||
constructor(props) {
|
||||
@ -17,6 +18,8 @@ class ModPackOverview extends React.Component {
|
||||
this.state = {
|
||||
listPacks: []
|
||||
}
|
||||
|
||||
this.mutex = locks.createMutex();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -65,13 +68,26 @@ class ModPackOverview extends React.Component {
|
||||
data: {name: inputValue},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
this_class.setState({
|
||||
listPacks: data.data.mod_packs
|
||||
});
|
||||
this_class.mutex.lock(() => {
|
||||
let packList = this_class.state.listPacks;
|
||||
|
||||
swal({
|
||||
title: "modpack created successfully",
|
||||
type: "success"
|
||||
data.data.mod_packs.forEach((v, k) => {
|
||||
if(v.name == inputValue) {
|
||||
packList.push(data.data.mod_packs[k]);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
listPacks: packList
|
||||
});
|
||||
|
||||
swal({
|
||||
title: "modpack created successfully",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
@ -109,14 +125,28 @@ class ModPackOverview extends React.Component {
|
||||
data: {name: name},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
this_class.setState({
|
||||
listPacks: data.data.mod_packs
|
||||
});
|
||||
if(data.success) {
|
||||
this_class.mutex.lock(() => {
|
||||
let mod_packs = this_class.state.listPacks;
|
||||
|
||||
swal({
|
||||
title: "Modpack deleted successfully",
|
||||
type: "success"
|
||||
});
|
||||
mod_packs.forEach((v, k) => {
|
||||
if(v.name == name) {
|
||||
delete mod_packs[k];
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
listPacks: mod_packs
|
||||
});
|
||||
|
||||
swal({
|
||||
title: "Modpack deleted successfully",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/packs/delete', status, err.toString());
|
||||
@ -184,12 +214,20 @@ class ModPackOverview extends React.Component {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
modPackToggleModHandler(e) {
|
||||
modPackToggleModHandler(e, updatesInProgress) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
if(updatesInProgress) {
|
||||
swal("Toggle mod failed", "Can't toggle the mod, when an update is still in progress", "error");
|
||||
return false;
|
||||
}
|
||||
|
||||
let $button = $(e.target);
|
||||
let $row = $button.parents("tr");
|
||||
let mod_name = $row.data("mod-name");
|
||||
let mod_pack = $row.parents(".single-modpack").find("h3").html();
|
||||
let this_class = this;
|
||||
|
||||
$.ajax({
|
||||
url: "/api/mods/packs/mod/toggle",
|
||||
@ -200,9 +238,28 @@ class ModPackOverview extends React.Component {
|
||||
},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
this.setState({
|
||||
listPacks: data.data.mod_packs
|
||||
});
|
||||
if(data.success) {
|
||||
this_class.mutex.lock(() => {
|
||||
let packList = this_class.state.listPacks;
|
||||
|
||||
packList.forEach((modPack, modPackKey) => {
|
||||
if(modPack.name == mod_pack) {
|
||||
packList[modPackKey].mods.mods.forEach((mod, modKey) => {
|
||||
if(mod.name == mod_name) {
|
||||
packList[modPackKey].mods.mods[modKey].enabled = data.data;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
listPacks: packList
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/packs/mod/toggle', status, err.toString());
|
||||
@ -215,8 +272,14 @@ class ModPackOverview extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
modPackDeleteModHandler(e) {
|
||||
modPackDeleteModHandler(e, updatesInProgress) {
|
||||
e.preventDefault();
|
||||
|
||||
if(updatesInProgress) {
|
||||
swal("Delete failed", "Can't delete the mod, when an update is still in progress", "error");
|
||||
return false;
|
||||
}
|
||||
|
||||
let $button = $(e.target);
|
||||
let $row = $button.parents("tr");
|
||||
let mod_name = $row.data("mod-name");
|
||||
@ -243,10 +306,30 @@ class ModPackOverview extends React.Component {
|
||||
},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
swal("Delete of mod " + mod_name + " inside modPack " + mod_pack + " successful", "", "success");
|
||||
class_this.setState({
|
||||
listPacks: data.data.mod_packs
|
||||
});
|
||||
if(data.success) {
|
||||
class_this.mutex.lock(() => {
|
||||
swal("Delete of mod " + mod_name + " inside modPack " + mod_pack + " successful", "", "success");
|
||||
|
||||
let packList = class_this.state.listPacks;
|
||||
|
||||
packList.forEach((modPack, modPackKey) => {
|
||||
if(modPack.name == mod_pack) {
|
||||
packList[modPackKey].mods.mods.forEach((mod, modKey) => {
|
||||
if(mod.name == mod_name) {
|
||||
delete packList[modPackKey].mods.mods[modKey];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
class_this.setState({
|
||||
listPacks: packList
|
||||
});
|
||||
|
||||
class_this.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/packs/mod/delete', status, err.toString());
|
||||
@ -299,9 +382,29 @@ class ModPackOverview extends React.Component {
|
||||
success: (data) => {
|
||||
toggleUpdateStatus();
|
||||
removeVersionAvailableStatus();
|
||||
this_class.setState({
|
||||
listPacks: data.data.mod_packs
|
||||
});
|
||||
|
||||
if(data.success) {
|
||||
this_class.mutex.lock(() => {
|
||||
let packList = this_class.state.listPacks;
|
||||
|
||||
packList.forEach((modPack, modPackKey) => {
|
||||
if(modPack.name == mod_pack) {
|
||||
packList[modPackKey].mods.mods.forEach((mod, modKey) => {
|
||||
if(mod.name == modname) {
|
||||
packList[modPackKey].mods.mods[modKey] = data.data;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
listPacks: packList
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/packs/mod/update', status, err.toString());
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import {IndexLink} from 'react-router';
|
||||
import ModOverview from './Mods/ModOverview.jsx';
|
||||
import locks from "locks";
|
||||
|
||||
class ModsContent extends React.Component {
|
||||
constructor(props) {
|
||||
@ -27,7 +28,9 @@ class ModsContent extends React.Component {
|
||||
logged_in: false,
|
||||
installedMods: null,
|
||||
updates_available: 0,
|
||||
}
|
||||
};
|
||||
|
||||
this.mutex = locks.createMutex();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -141,7 +144,7 @@ class ModsContent extends React.Component {
|
||||
success: (data) => {
|
||||
this_class.setState({
|
||||
installedMods: data.data.mods
|
||||
})
|
||||
});
|
||||
|
||||
swal({
|
||||
type: "success",
|
||||
@ -251,11 +254,18 @@ class ModsContent extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
toggleModHandler(e) {
|
||||
toggleModHandler(e, updatesInProgress) {
|
||||
e.preventDefault();
|
||||
|
||||
if(updatesInProgress) {
|
||||
swal("Toggle mod failed", "Can't toggle the mod, when an update is still in progress", "error");
|
||||
return false;
|
||||
}
|
||||
|
||||
let $button = $(e.target);
|
||||
let $row = $button.parents("tr");
|
||||
let mod_name = $row.data("mod-name");
|
||||
let this_class = this;
|
||||
|
||||
$.ajax({
|
||||
url: "/api/mods/toggle",
|
||||
@ -265,9 +275,23 @@ class ModsContent extends React.Component {
|
||||
},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
this.setState({
|
||||
installedMods: data.data
|
||||
});
|
||||
if(data.success) {
|
||||
this_class.mutex.lock(() => {
|
||||
let installedMods = this_class.state.installedMods;
|
||||
|
||||
$.each(installedMods, (k, v) => {
|
||||
if(v.name == mod_name) {
|
||||
installedMods[k].enabled = data.data;
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
installedMods: installedMods
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/toggle', status, err.toString());
|
||||
@ -280,8 +304,14 @@ class ModsContent extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteModHandler(e) {
|
||||
deleteModHandler(e, updatesInProgress) {
|
||||
e.preventDefault();
|
||||
|
||||
if(updatesInProgress) {
|
||||
swal("Delete failed", "Can't delete the mod, when an update is still in progress", "error");
|
||||
return false;
|
||||
}
|
||||
|
||||
let $button = $(e.target);
|
||||
let $row = $button.parents("tr");
|
||||
let mod_name = $row.data("mod-name");
|
||||
@ -306,10 +336,24 @@ class ModsContent extends React.Component {
|
||||
},
|
||||
dataType: "JSON",
|
||||
success: (data) => {
|
||||
swal("Delete of mod " + mod_name + " successful", "", "success");
|
||||
class_this.setState({
|
||||
installedMods: data.data
|
||||
});
|
||||
if(data.success) {
|
||||
class_this.mutex.lock(() => {
|
||||
swal("Delete of mod " + mod_name + " successful", "", "success");
|
||||
let installedMods = class_this.state.installedMods;
|
||||
|
||||
installedMods.forEach((v, k) => {
|
||||
if(v.name == mod_name) {
|
||||
delete installedMods[k];
|
||||
}
|
||||
});
|
||||
|
||||
class_this.setState({
|
||||
installedMods: installedMods
|
||||
});
|
||||
|
||||
class_this.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/delete', status, err.toString());
|
||||
@ -401,12 +445,26 @@ class ModsContent extends React.Component {
|
||||
toggleUpdateStatus();
|
||||
removeVersionAvailableStatus();
|
||||
|
||||
this_class.updatesAvailable();
|
||||
this_class.updateCountSubtract();
|
||||
|
||||
this_class.setState({
|
||||
installedMods: data.data.mods
|
||||
});
|
||||
if(data.success) {
|
||||
this_class.mutex.lock(() => {
|
||||
swal("Delete of mod " + modname + " successful", "", "success");
|
||||
let installedMods = this_class.state.installedMods;
|
||||
|
||||
installedMods.forEach((v, k) => {
|
||||
if(v.name == modname) {
|
||||
installedMods[k] = data.data;
|
||||
}
|
||||
});
|
||||
|
||||
this_class.setState({
|
||||
installedMods: installedMods
|
||||
});
|
||||
|
||||
this_class.mutex.unlock();
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (jqXHR, status, err) => {
|
||||
console.log('api/mods/delete', status, err.toString());
|
||||
@ -451,6 +509,26 @@ class ModsContent extends React.Component {
|
||||
}
|
||||
|
||||
uploadModSuccessHandler(event, data) {
|
||||
// let this_class = this;
|
||||
// console.log(data.response);
|
||||
//
|
||||
// if(data.response.success) {
|
||||
// this.mutex.lock(() => {
|
||||
// let installedMods = this_class.state.installedMods;
|
||||
// console.log(installedMods);
|
||||
// data.response.data.mods.forEach((key, mod) => {
|
||||
// if(!installedMods.find((sMod) => mod.name == sMod.name)) {
|
||||
// installedMods.push(mod);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// this_class.setState({
|
||||
// installedMods: installedMods
|
||||
// });
|
||||
//
|
||||
// this_class.mutex.unlock();
|
||||
// });
|
||||
// }
|
||||
this.setState({
|
||||
installedMods: data.response.data.mods
|
||||
});
|
||||
|
@ -15,6 +15,7 @@
|
||||
"babel-loader": "^6.2.1",
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"babel-preset-react": "^6.3.13",
|
||||
"locks": "^0.2.2",
|
||||
"react": "^15.0.1",
|
||||
"react-console-component": "^0.6.1",
|
||||
"react-dom": "^15.0.1",
|
||||
|
Loading…
Reference in New Issue
Block a user