Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
digibib
mycel-client
Commits
5ec1488c
Commit
5ec1488c
authored
Dec 20, 2021
by
bensinober
Browse files
Add server mutex lock and implement user update for minutes api
parent
ba5a0667
Changes
4
Show whitespace changes
Inline
Side-by-side
docs/TODO.md
View file @
5ec1488c
...
...
@@ -5,7 +5,6 @@
## Server
[ ] Rewrite auth against koha from SIP2 to something else
[ ] Use minutes from db instead of in-memory server, optionally add api for minutes for later server rewrite
[ ] Only use db for persistence, remove in-memory server clients
[ ] Simple ui for server updates
...
...
server/server.go
View file @
5ec1488c
...
...
@@ -9,6 +9,8 @@ import (
"log"
"net/http"
"net/url"
"strconv"
"sync"
"time"
_
"github.com/go-sql-driver/mysql"
...
...
@@ -44,6 +46,7 @@ type server struct {
db
*
DB
startTime
time
.
Time
clients
map
[
string
]
*
client
.
Client
// in-memory logged in clients
mu
sync
.
Mutex
}
func
newServer
(
conn
*
sql
.
DB
)
*
server
{
...
...
@@ -84,7 +87,9 @@ func (s *server) clientHandler(w http.ResponseWriter, r *http.Request) {
}
if
c
.
User
!=
nil
{
c
.
User
.
UpdateSeen
()
// for keep-alive
s
.
mu
.
Lock
()
s
.
clients
[
cname
]
=
c
// Update in memory client
s
.
mu
.
Unlock
()
}
b
,
err
:=
json
.
Marshal
(
c
)
if
err
!=
nil
{
...
...
@@ -107,7 +112,9 @@ func (s *server) clientHandler(w http.ResponseWriter, r *http.Request) {
http
.
Error
(
w
,
fmt
.
Sprintf
(
"Client not found in db, mac: %s, ip: %s"
,
mac
,
ip
),
http
.
StatusNotFound
)
return
}
s
.
mu
.
Lock
()
s
.
clients
[
c
.
Name
]
=
c
// TODO: in memory client list, unneccessary ?
s
.
mu
.
Unlock
()
b
,
err
:=
json
.
Marshal
(
c
)
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
...
...
@@ -144,8 +151,11 @@ func (s *server) logInHandler(w http.ResponseWriter, r *http.Request) {
u
:=
&
client
.
User
{
Type
:
"AnonymousUser"
,
Minutes
:
&
mins
}
u
.
UpdateSeen
()
c
.
SetUser
(
u
)
c
.
Client
=
&
c
.
Id
s
.
mu
.
Lock
()
s
.
clients
[
cname
]
=
c
// TODO: in memory client list, unneccessary ?
s
.
db
.
UpdateUser
(
c
)
s
.
mu
.
Unlock
()
s
.
db
.
UpdateUser
(
u
)
b
,
err
:=
json
.
Marshal
(
c
)
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
...
...
@@ -193,19 +203,39 @@ func (s *server) logInHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Insert or Update user
in db
based on login response
// Insert or Update user
response
based on login response
u
,
err
:=
s
.
db
.
UpsertUser
(
c
,
authUser
)
if
err
!=
nil
{
log
.
Println
(
err
)
http
.
Error
(
w
,
"Failed decoding auth response."
,
http
.
StatusInternalServerError
)
return
}
// client specific auth tests
switch
{
case
!
authUser
.
Authenticated
:
u
.
Message
=
"Feil lånenummer/brukernavn eller PIN/passord"
case
*
u
.
Minutes
<=
0
:
u
.
Message
=
"Beklager, du har brukt opp kvoten din for i dag!"
case
u
.
Age
<
*
c
.
Options
.
AgeL
:
case
u
.
Age
>
*
c
.
Options
.
AgeH
:
u
.
Message
=
fmt
.
Sprintf
(
"Denne maskinen er kun for de mellom %d og %d"
,
c
.
Options
.
AgeL
,
c
.
Options
.
AgeH
)
default
:
u
.
Authenticated
=
authUser
.
Authenticated
}
u
.
Minutes
=
authUser
.
Minutes
u
.
Client
=
&
c
.
Id
u
.
UpdateSeen
()
c
.
SetUser
(
u
)
s
.
db
.
UpdateUser
(
c
)
// dont actually add user if not allowed use
if
u
.
Authenticated
{
s
.
db
.
UpdateUser
(
u
)
s
.
mu
.
Lock
()
s
.
clients
[
cname
]
=
c
// TODO: in memory client list, unneccessary ?
s
.
mu
.
Unlock
()
}
b
,
err
:=
json
.
Marshal
(
c
)
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
...
...
@@ -231,16 +261,66 @@ func (s *server) logOutHandler(w http.ResponseWriter, r *http.Request) {
return
}
log
.
Printf
(
"POST /api/logout from client: %s"
,
cname
)
c
.
User
.
Client
=
nil
if
_
,
err
:=
s
.
db
.
RemoveClientActiveUser
(
c
.
User
.
Id
);
err
!=
nil
{
http
.
Error
(
w
,
"Failed removing client active user."
,
http
.
StatusInternalServerError
)
return
}
c
.
SetUser
(
nil
)
s
.
mu
.
Lock
()
s
.
clients
[
cname
]
=
c
// TODO: in memory client list, unneccessary ?
s
.
mu
.
Unlock
()
w
.
Write
([]
byte
(
"OK"
))
}
// POST /api/users/update : update existing user
func
(
s
*
server
)
updateUserHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
username
:=
r
.
FormValue
(
"username"
)
name
:=
r
.
FormValue
(
"name"
)
minutes
:=
r
.
FormValue
(
"minutes"
)
if
username
==
""
{
http
.
Error
(
w
,
"Missing parameter username!"
,
http
.
StatusBadRequest
)
}
u
,
err
:=
s
.
db
.
GetUserByUsername
(
username
)
if
u
.
Id
==
0
{
http
.
Error
(
w
,
"User not found"
,
http
.
StatusNotFound
)
return
}
if
err
!=
nil
{
http
.
Error
(
w
,
"Failed getting user."
,
http
.
StatusInternalServerError
)
return
}
log
.
Printf
(
"POST /api/users/update for username: %s, minutes: %s"
,
username
,
minutes
)
if
name
!=
""
{
u
.
Name
=
&
name
}
if
minutes
!=
""
{
if
m
,
err
:=
strconv
.
Atoi
(
minutes
);
err
==
nil
{
u
.
Minutes
=
&
m
}
}
s
.
db
.
UpdateUser
(
u
)
if
u
.
Client
!=
nil
{
c
,
err
:=
s
.
db
.
GetClient
(
u
.
Client
)
if
err
!=
nil
{
http
.
Error
(
w
,
"Failed getting user."
,
http
.
StatusInternalServerError
)
return
}
c
.
User
=
u
s
.
mu
.
Lock
()
s
.
clients
[
c
.
Name
]
=
c
// TODO: in memory client list, unneccessary ?
s
.
mu
.
Unlock
()
}
b
,
err
:=
json
.
Marshal
(
u
)
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
w
.
Write
(
b
)
}
// POST /api/queue : add item to queue
func
(
s
*
server
)
queueHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
q
client
.
Queue
...
...
@@ -319,7 +399,9 @@ func (s *server) addItemToClientQueue(q client.Queue) error {
q
.
Time
=
time
.
Now
()
q
.
Uuid
=
uuid
.
New
()
c
.
Queue
=
append
(
c
.
Queue
,
q
)
s
.
mu
.
Lock
()
s
.
clients
[
q
.
Client
]
=
c
s
.
mu
.
Unlock
()
}
else
{
return
errors
.
New
(
"No matching client"
)
...
...
@@ -333,7 +415,9 @@ func (s *server) updateClientQueueItem(q client.Queue) error {
for
i
,
cq
:=
range
c
.
Queue
{
if
cq
.
Uuid
==
q
.
Uuid
{
q
.
Time
=
time
.
Now
()
s
.
mu
.
Lock
()
s
.
clients
[
q
.
Client
]
.
Queue
[
i
]
=
q
s
.
mu
.
Unlock
()
}
}
}
else
{
...
...
@@ -360,7 +444,7 @@ func (s *server) DecreaseTime() {
if
c
.
User
!=
nil
{
if
c
.
User
.
SeenLastMinute
()
{
*
c
.
User
.
Minutes
--
s
.
db
.
UpdateUser
(
c
)
s
.
db
.
UpdateUser
(
c
.
User
)
}
else
{
if
_
,
err
:=
s
.
db
.
RemoveClientActiveUser
(
c
.
User
.
Id
);
err
!=
nil
{
log
.
Println
(
"Failed force log out of user"
,
c
.
User
.
Id
)
...
...
@@ -368,7 +452,9 @@ func (s *server) DecreaseTime() {
log
.
Println
(
"Force logout of inactive user:"
,
c
.
User
.
Username
)
c
.
SetUser
(
nil
)
}
s
.
mu
.
Lock
()
s
.
clients
[
name
]
=
c
s
.
mu
.
Unlock
()
}
}
}
...
...
@@ -396,9 +482,13 @@ func main() {
go
s
.
ticker
()
mux
:=
http
.
NewServeMux
()
mux
.
HandleFunc
(
"/.status"
,
s
.
statusHandler
)
// Client API
mux
.
HandleFunc
(
"/api/clients"
,
s
.
clientHandler
)
// client start / status endpoint
mux
.
HandleFunc
(
"/api/login"
,
s
.
logInHandler
)
// client logon
mux
.
HandleFunc
(
"/api/logout"
,
s
.
logOutHandler
)
// client logoff
// User API
mux
.
HandleFunc
(
"/api/user/update"
,
s
.
updateUserHandler
)
// user update (username,name,minutes)
// Queue API
mux
.
HandleFunc
(
"/api/queue"
,
s
.
queueHandler
)
// server initiated commands
mux
.
HandleFunc
(
"/api/updatequeue"
,
s
.
queueResponseHandler
)
// Response to server initiated commands
...
...
window/login.go
View file @
5ec1488c
...
...
@@ -60,32 +60,17 @@ func Login(w fyne.Window, st *Status, hostAPI, name string, extraMinutes, agel,
return
}
cl
,
err
:=
authenticate
(
hostAPI
,
name
,
username
.
Text
,
password
.
Text
)
user
:=
cl
.
User
// Unknown error gives general failed login
if
err
!=
nil
{
log
.
Println
(
"authentication API call failed: "
,
err
)
errDiv
.
Text
=
"Feil lånenummer/brukernavn eller PIN/passord"
errDiv
.
Refresh
()
return
}
if
!
user
.
Authenticated
{
errDiv
.
Text
=
user
.
Message
errDiv
.
Refresh
()
return
}
uMins
:=
*
user
.
Minutes
if
uMins
+
extraMinutes
<=
0
&&
user
.
Type
!=
"G"
{
log
.
Println
(
extraMinutes
)
errDiv
.
Text
=
"Beklager, du har brukt opp kvoten din for i dag!"
errDiv
.
Refresh
()
return
}
if
user
.
Type
==
"G"
&&
uMins
<=
0
{
errDiv
.
Text
=
"Beklager, du har brukt opp kvoten din for i dag!"
errDiv
.
Refresh
()
return
}
if
user
.
Age
<
agel
||
user
.
Age
>
ageh
{
errDiv
.
Text
=
fmt
.
Sprintf
(
"Denne maskinen er kun for de mellom %d og %d"
,
agel
,
ageh
)
// Display error
if
!
cl
.
User
.
Authenticated
{
errDiv
.
Text
=
cl
.
User
.
Message
errDiv
.
Refresh
()
return
}
...
...
@@ -97,7 +82,7 @@ func Login(w fyne.Window, st *Status, hostAPI, name string, extraMinutes, agel,
password
.
Refresh
()
w
.
SetFullScreen
(
false
)
w
.
Hide
()
st
.
SetMinutes
(
uMin
s
)
st
.
SetMinutes
(
*
cl
.
User
.
Minute
s
)
st
.
ShowStatusWindow
()
return
}
...
...
window/status.go
View file @
5ec1488c
...
...
@@ -3,6 +3,7 @@ package window
import
(
"bytes"
"encoding/json"
"errors"
"fmt"
"image/color"
"log"
...
...
@@ -44,10 +45,12 @@ func NewStatus(w, m fyne.Window, api string, c *client.Client, mins int) *Status
func
(
st
*
Status
)
logout
()
error
{
resp
,
err
:=
http
.
Get
(
fmt
.
Sprintf
(
"%s/api/logout?client=%s"
,
st
.
hostApi
,
st
.
client
.
Name
))
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
http
.
StatusOK
{
if
err
!=
nil
{
return
err
}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
errors
.
New
(
"Failed logging out"
)
}
return
nil
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment