2020-08-25 19:09:46 +00:00
local disknet = disknet or { }
2019-05-02 00:51:40 +00:00
2019-05-02 04:04:12 +00:00
local tArg = { ... }
2019-05-02 01:32:11 +00:00
2020-04-02 22:47:11 +00:00
disknet.mainPath = " disk/DISKNET " -- path of shared file
local limitChannelsToModem = false -- if true, can only use number channels from 1 to 65535
2020-11-28 05:52:55 +00:00
local checkDelay = 0.2 -- amount of time (seconds) between checking the file -- if 0, checks super fast so don't do that
2020-04-02 22:47:11 +00:00
local maximumBufferSize = 64 -- largest amount of messages per channel buffered
local isUsingTweaked = false
if _HOST then
2020-11-28 06:07:52 +00:00
if _HOST : find ( " CCEmuX " ) or _HOST : find ( " CC:Tweaked " ) or _HOST : find ( " [(]Minecraft " ) then
2020-04-02 22:47:11 +00:00
isUsingTweaked = true
end
end
2019-05-02 04:04:12 +00:00
2019-05-02 00:51:40 +00:00
local openChannels = { }
local yourID = os.getComputerID ( )
2019-05-02 04:04:12 +00:00
local uniqueID = math.random ( 1 , 2 ^ 31 - 1 ) -- prevents receiving your own messages
2020-08-25 19:09:46 +00:00
disknet.msgCheckList = { } -- makes sure duplicate messages aren't received
local ageToToss = 0.005 -- amount of time before a message is removed
2019-05-02 00:51:40 +00:00
2020-08-25 19:09:46 +00:00
-- used for synching times between different emulators
2020-02-01 10:21:35 +00:00
disknet._timeMod = 0
2020-04-02 23:10:27 +00:00
-- do not think for one second that os.epoch("utc") would be a proper substitute
2019-05-02 00:51:40 +00:00
local getTime = function ( )
2020-08-25 19:09:46 +00:00
if os.day then
return ( os.time ( ) + ( - 1 + os.day ( ) ) * 24 ) + disknet._timeMod
else
return os.time ( ) + disknet._timeMod
end
2019-05-02 00:51:40 +00:00
end
2020-04-02 23:10:27 +00:00
local function serialize ( tbl )
local output = " { "
local noKlist = { }
local cc = table.concat
for i = 1 , # tbl do
if type ( tbl [ i ] ) == " table " then
output = output .. serialize ( tbl [ i ] )
elseif type ( tbl [ i ] ) == " string " then
output = cc ( { output , " \" " , tbl [ i ] , " \" " } )
else
output = output .. tbl [ i ]
end
noKlist [ i ] = true
output = output .. " , "
end
for k , v in pairs ( tbl ) do
if not noKlist [ k ] then
if type ( k ) == " number " or type ( k ) == " table " then
output = cc ( { output , " [ " , k , " ]= " } )
else
output = cc ( { output , k , " = " } )
end
if type ( v ) == " table " then
output = output .. serialize ( v )
elseif type ( v ) == " string " then
output = cc ( { output , " \" " , v , " \" " } )
else
output = output .. v
end
output = output .. " , "
end
end
return output : sub ( 1 , - 2 ) : gsub ( " \n " , " \\ n " ) .. " } "
end
2019-05-02 04:04:12 +00:00
local readFile = function ( path )
local file = fs.open ( path , " r " )
local contents = file.readAll ( )
file.close ( )
return contents
end
local writeFile = function ( path , contents )
local file = fs.open ( path , " w " )
file.write ( contents )
file.close ( )
end
-- if 'limitChannelsToModem', then will make sure that channel is a number between 0 and 65535
2019-05-02 00:51:40 +00:00
local checkValidChannel = function ( channel )
if limitChannelsToModem then
if type ( channel ) == " number " then
if channel < 0 or channel > 65535 then
return false , " channel must be between 0 and 65535 "
else
return true
end
else
return false , " channel must be number "
end
else
if type ( channel ) == " string " or type ( channel ) == " number " then
return true
else
return false , " channel must be castable to string "
end
end
end
disknet.isOpen = function ( channel )
local valid , grr = checkValidChannel ( channel )
if valid then
for i = 1 , # openChannels do
if openChannels [ i ] == channel then
return true
end
end
return false
else
error ( grr )
end
end
2020-08-25 19:09:46 +00:00
isOpen = disknet.isOpen
2019-05-02 00:51:40 +00:00
disknet.open = function ( channel )
local valid , grr = checkValidChannel ( channel )
if valid then
openChannels [ # openChannels + 1 ] = channel
return true
else
error ( grr )
end
end
2020-08-25 19:09:46 +00:00
open = disknet.open
2019-05-02 00:51:40 +00:00
disknet.close = function ( channel )
local valid , grr = checkValidChannel ( channel )
if valid then
for i = 1 , # openChannels do
if openChannels [ i ] == channel then
table.remove ( openChannels , i )
return true
end
end
return false
else
error ( grr )
end
end
2020-08-25 19:09:46 +00:00
close = disknet.close
2019-05-02 00:51:40 +00:00
disknet.closeAll = function ( )
openChannels = { }
end
2020-08-25 19:09:46 +00:00
closeAll = disknet.closeAll
2019-05-02 00:51:40 +00:00
2019-05-07 21:49:48 +00:00
disknet.send = function ( channel , message , recipient )
2019-05-02 00:51:40 +00:00
local valid , grr = checkValidChannel ( channel )
if valid then
2019-05-02 04:17:37 +00:00
if not fs.exists ( fs.combine ( disknet.mainPath , tostring ( channel ) ) ) then
2020-08-25 19:09:46 +00:00
fs.makeDir ( disknet.mainPath )
2019-05-02 04:17:37 +00:00
fs.open ( fs.combine ( disknet.mainPath , tostring ( channel ) ) , " w " ) . close ( )
end
2019-05-02 04:04:12 +00:00
local contents = textutils.unserialize ( readFile ( fs.combine ( disknet.mainPath , tostring ( channel ) ) ) )
2019-05-08 20:56:36 +00:00
local cTime = getTime ( )
2019-05-02 00:51:40 +00:00
if disknet.isOpen ( channel ) then
2019-05-02 04:04:12 +00:00
local file = fs.open ( fs.combine ( disknet.mainPath , tostring ( channel ) ) , " w " )
if contents then
contents [ # contents + 1 ] = {
2019-05-08 20:56:36 +00:00
time = cTime ,
2019-05-02 04:04:12 +00:00
id = yourID ,
uniqueID = uniqueID ,
messageID = math.random ( 1 , 2 ^ 31 - 1 ) ,
channel = channel ,
2019-05-07 21:49:48 +00:00
recipient = recipient ,
2019-05-02 04:04:12 +00:00
message = message ,
}
2019-05-08 20:56:36 +00:00
for i = # contents , 1 , - 1 do
if cTime - ( contents [ i ] . time or 0 ) > ageToToss then
table.remove ( contents , i )
end
end
2019-05-02 04:04:12 +00:00
if # contents > maximumBufferSize then
table.remove ( contents , 1 )
end
2020-04-02 23:10:27 +00:00
file.write ( serialize ( contents ) )
2019-05-02 04:04:12 +00:00
else
2020-04-02 23:10:27 +00:00
file.write ( serialize ( { {
2019-05-08 20:56:36 +00:00
time = cTime ,
2019-05-02 04:04:12 +00:00
id = yourID ,
uniqueID = uniqueID ,
messageID = math.random ( 1 , 2 ^ 31 - 1 ) ,
channel = channel ,
message = message ,
2020-04-02 22:47:11 +00:00
} } ) : gsub ( " \n [ ]* " , " " ) )
2019-05-02 04:04:12 +00:00
end
2019-05-02 00:51:40 +00:00
file.close ( )
return true
else
return false
end
else
error ( grr )
end
end
2020-08-25 19:09:46 +00:00
send = disknet.send
2019-05-02 00:51:40 +00:00
2019-05-08 20:56:36 +00:00
local fList , pList , sList = { } , { } , { }
2019-05-02 04:04:12 +00:00
local loadFList = function ( )
fList , pList = { } , { }
if channel then
fList = { fs.open ( fs.combine ( disknet.mainPath , tostring ( channel ) ) , " r " ) }
pList = { fs.combine ( disknet.mainPath , tostring ( channel ) ) }
else
for i = 1 , # openChannels do
fList [ i ] = fs.open ( fs.combine ( disknet.mainPath , tostring ( openChannels [ i ] ) ) , " r " )
pList [ i ] = fs.combine ( disknet.mainPath , tostring ( openChannels [ i ] ) )
end
end
end
2020-08-25 19:09:46 +00:00
-- returns: string message, string/number channel, number senderID, number timeThatMessageWasSentAt
2019-05-08 20:56:36 +00:00
disknet.receive = function ( channel , senderFilter )
2019-05-02 00:51:40 +00:00
local valid , grr = checkValidChannel ( channel )
if valid or not channel then
2019-05-02 15:00:43 +00:00
2019-05-02 04:04:12 +00:00
local output , contents
local doRewrite = false
2019-05-02 15:00:43 +00:00
2019-05-02 15:13:42 +00:00
local good , goddamnit = pcall ( function ( )
2019-05-08 20:56:36 +00:00
local cTime = getTime ( )
2020-04-02 22:47:11 +00:00
local goWithIt = false
2019-05-02 15:13:42 +00:00
while true do
2019-05-08 20:56:36 +00:00
loadFList ( )
2019-05-02 15:13:42 +00:00
for i = 1 , # fList do
contents = fList [ i ] . readAll ( )
if contents ~= " " then
2019-05-08 20:56:36 +00:00
contents = textutils.unserialize ( contents )
2019-05-02 15:13:42 +00:00
if type ( contents ) == " table " then
if contents [ 1 ] then
if not output then
for look = 1 , # contents do
2020-08-25 19:09:46 +00:00
if ( contents [ look ] . uniqueID ~= uniqueID ) and ( not disknet.msgCheckList [ contents [ look ] . messageID ] ) then -- make sure you're not receiving messages that you sent
2019-05-08 20:56:36 +00:00
if ( not contents [ look ] . recipient ) or contents [ look ] . recipient == yourID then -- make sure that messages intended for others aren't picked up
if ( not channel ) or channel == contents [ look ] . channel then -- make sure that messages are the same channel as the filter, if any
if ( not senderFilter ) or senderFilter == contents [ look ] . id then -- make sure that the sender is the same as the id filter, if any
2020-04-02 22:47:11 +00:00
if ( not isUsingTweaked ) and math.abs ( contents [ look ] . time - getTime ( ) ) >= ageToToss then -- if using something besides CC:Tweaked/CCEmuX, adjust your time.
disknet._timeMod = contents [ look ] . time - getTime ( )
cTime = getTime ( )
goWithIt = true
end
if cTime - ( contents [ look ] . time or 0 ) <= ageToToss or goWithIt then -- make sure the message isn't too old
2020-08-25 19:09:46 +00:00
disknet.msgCheckList [ contents [ look ] . messageID ] = true
2019-05-08 20:56:36 +00:00
output = { }
for k , v in pairs ( contents [ look ] ) do
output [ k ] = v
end
break
end
2019-05-07 21:49:48 +00:00
end
2019-05-02 15:13:42 +00:00
end
2019-05-02 04:53:13 +00:00
end
2019-05-02 04:35:01 +00:00
end
2019-05-02 04:04:12 +00:00
end
end
2019-05-02 15:00:43 +00:00
2019-05-02 15:13:42 +00:00
-- delete old msesages
doRewrite = false
for t = # contents , 1 , - 1 do
2020-04-02 22:47:11 +00:00
if cTime - ( contents [ t ] . time or 0 ) > ageToToss or cTime - ( contents [ t ] . time or 0 ) < - 1 then
2020-08-25 19:09:46 +00:00
disknet.msgCheckList [ contents [ t ] . messageID ] = nil
2019-05-02 15:13:42 +00:00
table.remove ( contents , t )
doRewrite = true
end
2019-05-02 04:04:12 +00:00
end
2019-05-02 15:13:42 +00:00
if doRewrite then
2020-04-02 23:10:27 +00:00
writeFile ( pList [ i ] , serialize ( contents ) )
2019-05-02 15:13:42 +00:00
end
if output then
break
2019-05-02 04:04:12 +00:00
end
end
end
end
2019-05-02 00:51:40 +00:00
end
2019-05-02 15:13:42 +00:00
if output then
break
else
2020-04-02 22:47:11 +00:00
if checkDelay > 0 then
sleep ( checkDelay )
2019-05-09 05:56:23 +00:00
else
os.queueEvent ( " " )
os.pullEvent ( " " )
end
2019-05-02 15:13:42 +00:00
end
2019-05-08 20:56:36 +00:00
for i = 1 , # fList do
fList [ i ] . close ( )
end
fList , pList = { } , { }
2019-05-02 00:51:40 +00:00
end
2019-05-02 15:13:42 +00:00
end )
if good then
if contents then
2020-04-02 22:47:11 +00:00
return output.message , output.channel , output.id , output.time + disknet._timeMod
2019-05-02 00:51:40 +00:00
else
2019-05-02 15:13:42 +00:00
return nil
2019-05-02 00:51:40 +00:00
end
else
2019-05-02 15:13:42 +00:00
for i = 1 , # fList do
fList [ i ] . close ( )
end
error ( goddamnit , 0 )
2019-05-02 00:51:40 +00:00
end
else
error ( grr )
end
end
2020-08-25 19:09:46 +00:00
receive = disknet.receive
2019-05-02 00:51:40 +00:00
2020-04-02 22:47:11 +00:00
-- not really needed if going between CCEmuX and another emulator, but may be needed between two separate CCEmuX daemons
2020-02-01 10:21:35 +00:00
disknet.receive_TS = function ( ... )
local message , channel , id , time = disknet.receive ( ... )
if time then
disknet._timeMod = time - getTime ( )
end
return message , channel , id , time
end
2020-08-25 19:09:46 +00:00
receive_TS = disknet.receive_TS
2020-02-01 10:21:35 +00:00
2019-05-02 00:51:40 +00:00
return disknet