ifcurrentPlaceValue>=len(numberToChar){return"",fmt.Errorf("Failed to generate usercode %d to string, currentPlaceValue %d and length of number to char %d in place %d",code,currentPlaceValue,len(numberToChar),place)}
toReturn[index]=numberToChar[currentPlaceValue]
}
returnstring(toReturn[:]),nil
}
funcParseUserCode(sstring)(UserCode,error){
asRune:=[]rune(s)
iflen(asRune)!=4{return0,fmt.Errorf("String to deconvert is not of length 4: %s",s)}
vartoReturnUserCode=0
forplace:=3;place>=0;place--{
index:=3-place
curDigitNum:=0
found:=false
fori,letter:=rangenumberToChar{
ifletter==asRune[index]{
curDigitNum=i
found=true
}
}
if!found{return0,fmt.Errorf("Failed to find place's number %s",s)}
// BoughtType values. do not reorganize these or you fuck up the database
@ -32,14 +33,13 @@ const (
MaxCodes=36*36*36*36
)
typeuserCodeint
typeUserstruct{
CreatedAttime.Time
UpdatedAttime.Time
DeletedAtgorm.DeletedAt`gorm:"index"`
CodeuserCode `gorm:"primaryKey"`// of maximum value max codes, incremented one by one. These are converted to 4 digit alphanumeric code users can remember/use
Codecodes.UserCode `gorm:"primaryKey"`// of maximum value max codes, incremented one by one. These are converted to 4 digit alphanumeric code users can remember/use
BoughtTimeint64// unix time. Used to figure out if the pass is still valid
// converting to base 36 (A-Z + numbers) then into characters, then appending
fordigit:=3;digit>=0;digit--{
currentPlaceValue:=value/intPow(36,digit)
value-=currentPlaceValue*intPow(36,digit)
ifcurrentPlaceValue>=len(numberToChar){return"",fmt.Errorf("Failed to generate usercode %d to string, currentPlaceValue %d and length of number to char %d",code,currentPlaceValue,len(numberToChar))}
toReturn+=string(numberToChar[currentPlaceValue])
vardaypassTimedOut=make(map[codes.UserCode]int64)// value is time last requested, rate limiting by day pass. If exists is rate limited, should be removed when ok to request again
// for 10 free minutes a day, is when ip address began requesting
varipAddyTenFree=make(map[string]int64)
funccleanTimedOut(){
fork,v:=rangedaypassTimedOut{
ifcurrentTime()-v>1{
delete(daypassTimedOut,k)
}
}
returntoReturn,nil;
}
funcparseUserCode(sstring)(userCode,error){
asRune:=[]rune(s)
iflen(asRune)!=4{return0,fmt.Errorf("String to deconvert is not of length 4: %s",s)}
vartoReturnuserCode=0
fordigit:=3;digit>=0;digit--{
curDigitNum:=0
found:=false
fori,letter:=rangenumberToChar{
ifletter==asRune[digit]{
curDigitNum=i
found=true
}
fork,v:=rangeipAddyTenFree{
ifcurrentTime()-v>24*60*60{
delete(ipAddyTenFree,k)
}
if!found{return0,fmt.Errorf("Failed to find digit's number %s",s)}
toReturn+=userCode(curDigitNum*intPow(36,digit))
}
returntoReturn,nil
}
funcisUserOld(userUser)bool{
return(currentTime()-user.BoughtTime)>24*60*60
}
@ -110,7 +82,7 @@ func clearOld(db *gorm.DB) {
ifresult.Error!=nil{
log.Fatal(result.Error)
}
vartoDelete[]userCode // codes
vartoDelete[]codes.UserCode // codes
for_,user:=rangeusers{
ifuser.BoughtType!=0{
panic("Don't know how to handle bought type "+string(user.BoughtType)+" yet")
// now have valid user, in the database, to be rate limit checked
// rate limiting based on user token
_,exists:=daypassTimedOut[thisUserCode]
ifexists{
rejected=true
}else{
rejected=false
daypassTimedOut[thisUserCode]=currentTime()
}
}
}
}
@ -381,7 +377,7 @@ func main() {
http.HandleFunc("/checkout",checkout)
portString:=":8090"
log.Println("Serving on " +portString+"...")
log.Println("DO NOT RUN WITH CLOUDFLARE PROXY it rate limits based on IP, if behind proxy every IP will be the same. Would need to fix req.RemoteAddr. Serving on " +portString+"...")
<h1>AI is expensive so you need to pay for it</h1>
<p>You can play for free 10 minutes per day</p>
<p>You can play free 10 minutes a day. If you're seeing this you must buy a day pass to continue. If you already bought one, but are still seeing this, check that the code matches up. If you're unsatisfied with your service, you can get a refund via the email stripe sent you.</p>